|
This thread is locked; no one can reply to it. |
1
2
|
initializing temporary from result of ... |
Billybob
Member #3,136
January 2003
|
I'm creating a class template that will give me thread-safe primitives:
Whenever the value needs to be accessed a lock is put on it. So I can seamless access the value as if it were the original primitive, and yet it's completely thread-safe. However, when I try to compile my project I can an error on the line that initializes a static member of my Manager class. SafeValue<bool> Manager::executing = false;
manager.cpp:4: error: no matching function for call to ‘SafeValue<bool>::SafeValue(SafeValue<bool>)’ safe_value.h:17: note: candidates are: SafeValue<T>::SafeValue(SafeValue<T>&) [with T = bool] safe_value.h:16: note: SafeValue<T>::SafeValue(T) [with T = bool] manager.cpp:4: error: initializing temporary from result of ‘SafeValue<T>::SafeValue(T) [with T = bool]’ Now, the issue disappears if I do this: //SafeValue(SafeValue<T> &other) : x(other), lock() {} SafeValue(const SafeValue<T> &other) : x(other.x), lock() {} but that isn't thread-safe, and there's no way for me to lock a const SafeValue<T>. Any ideas?
|
kazzmir
Member #1,786
December 2001
|
SafeValue<bool> Manager::executing; executing = false; Something is strange about using = when you declare an object, but I dont remember what it is. Anyway, that works. |
Kibiz0r
Member #6,203
September 2005
|
I think false is being implicitly converted to SafeValue<bool>... make SafeValue(T y) explicit? --- |
Kitty Cat
Member #2,815
October 2002
|
Defining 'Type foo = bar;' Will call Type's constructor with the 'bar' as the parameter. However, you only have a SafeValue<T>& as a contructor argument, and 'false' can't be converted to a reference. You can try having -- |
Billybob
Member #3,136
January 2003
|
Quote: should be fine That's the code I'd like to use, because it is thread safe, but it won't work because x(other) calls the casting operator of other which is not const.
|
Kitty Cat
Member #2,815
October 2002
|
See my edits. I post too fast. -- |
Billybob
Member #3,136
January 2003
|
I've tried a whole bunch of different constructors now with no success. (except, of course, the ones that aren't thread-safe). It seems that no matter what, the compiler wants to use the copy constructor here:
|
Kibiz0r
Member #6,203
September 2005
|
Quote: I think false is being implicitly converted to SafeValue<bool>... make SafeValue(T y) explicit?
--- |
kazzmir
Member #1,786
December 2001
|
Uhm.. you are still having a problem? Did you notice my post? |
Billybob
Member #3,136
January 2003
|
Quote: Uhm.. you are still having a problem? Did you notice my post? Yes, but my goal is to make the class seamless. Quote: I think false is being implicitly converted to SafeValue<bool>... make SafeValue(T y) explicit? Sorry for being dense but, how would I do that?
|
Kitty Cat
Member #2,815
October 2002
|
Quote: I think false is being implicitly converted to SafeValue<bool> The problem is, it isn't. The compiler recognizes that false can be used to instantiate a SafeValue<bool> object which can then be passed to the correct constructor, however there is no explicit object and thus can't be passed as a reference. -- |
Kibiz0r
Member #6,203
September 2005
|
Quote: Sorry for being dense but, how would I do that?
explicit SafeValue(T y)
Quote: The problem is, it isn't. The compiler recognizes that false can be used to instantiate a SafeValue<bool> object which can then be passed to the correct constructor, however there is no explicit object and thus can't be passed as a reference. I'm assuming that this is what's really going on: SafeValue<bool> Manager::executing(SafeValue<bool>(false)); If that's right, what you're saying makes sense -- but I don't see how what I proposed is at odds with what you've said. Making it explicit would make the call into this: SafeValue<bool> Manager::executing(false); (At least, I think so.) And that is the intended result, isn't it? Also, Quote: but that isn't thread-safe, and there's no way for me to lock a const SafeValue<T>. I don't know thread-safety very well, but I do know you can make the lock mutable so you can perform non-const operations on it in a const context. --- |
Kitty Cat
Member #2,815
October 2002
|
Quote:
I'm assuming that this is what's really going on:
No, the problem is it's not doing that. It's basically doing: SafeValue<bool> Manager::executing(false); // and SafeValue<bool> Manager::executing = false; to work. -- |
CGamesPlay
Member #2,559
July 2002
|
Not related to your problem, but important nevertheless: this class does not make the variable thread-safe. You will still have race conditions: if(executing) { executing = false; // stop the execution } The read could occur, then another thread could modify the value before you set the value yourself. The only way to avoid that is to hold the lock until you are done with it. I recommend this sort of construct: #define lock(obj, block) \ obj.lock(); \ try { block } \ finally { \ obj.unlock(); \ } lock(executing, if(executing) { executing = false; // stop executing } )
-- Ryan Patterson - <http://cgamesplay.com/> |
Kibiz0r
Member #6,203
September 2005
|
CGames: What is "finally"? --- |
Tobias Dammers
Member #2,604
August 2002
|
finally defines a block that is executed after a try-catch structure, no matter whether an exception has occurred or not. The general structure is: try { // this executes until an exception is thrown } catch (exception foo) { // this executes only if a certain exception was thrown } finally { // this executes either after the try block finishes without exceptions, or // after all catch () blocks have been checked. } I'm not 100% positive whether 'finally' is Java-only or if C++ has it too. --- |
CGamesPlay
Member #2,559
July 2002
|
Ah, yeah. C++ you have to do this: catch(...) { obj.unlock(); throw; }
-- Ryan Patterson - <http://cgamesplay.com/> |
Tobias Dammers
Member #2,604
August 2002
|
Hm, but that wouldn't unlock the object if all goes well, would it? One would have to add another obj.unlock() after the last catch block. --- |
CGamesPlay
Member #2,559
July 2002
|
Ah, again, you are right #define lock(obj, block) { \ obj.lock(); \ try { \ { block } \ obj.unlock(); \ } \ catch(...) { \ obj.unlock(); \ throw; \ } }
-- Ryan Patterson - <http://cgamesplay.com/> |
Tobias Dammers
Member #2,604
August 2002
|
I'd say: #define lock(obj, block) { \ obj.lock(); \ try { \ block \ } \ catch(...) { \ obj.unlock(); \ throw; \ } \ obj.unlock(); \ } But I guess that's just personal taste. --- |
Kibiz0r
Member #6,203
September 2005
|
Could rip off the Boost scoped_lock model and make a stack object that unlocks it when it gets destructor'd. --- |
Billybob
Member #3,136
January 2003
|
Oh C++, why can't you be like Java? Or Java, why can't you not suck? I'm probably just going to scrap this idea and go back to regular brute-force locking Thanks for all the help though. It's much appreciated
|
axilmar
Member #1,204
April 2001
|
Quote: Whenever the value needs to be accessed a lock is put on it. So I can seamless access the value as if it were the original primitive, and yet it's completely thread-safe. ... but that isn't thread-safe, and there's no way for me to lock a const SafeValue<T>. Any ideas?
Copy constructors require the source object to be const; it's a C++ standard.
I have coded the assignment operator for you as well, just to be on the safe side. Here is the synchronized statement for C++: |
Billybob
Member #3,136
January 2003
|
Wow, I never knew about the mutable keyword. That'll come in handy! Thanks a lot axilmar Awesome article on synchronized too.
|
Kibiz0r
Member #6,203
September 2005
|
Quote: Wow, I never knew about the mutable keyword. You would if you didn't ignore my posts... Quote: I don't know thread-safety very well, but I do know you can make the lock mutable so you can perform non-const operations on it in a const context.
--- |
|
1
2
|