shared_ptr as reference argument
Is there some utility in passing shared_ptr's as references as here: void bla(boost::shared_ptr<T>& bla_ptr); This avoids creating of a new object and copying overhead, but is it safe? When would you recommend it and when not?
AMDG anony wrote:
Is there some utility in passing shared_ptr's as references as here:
void bla(boost::shared_ptr<T>& bla_ptr);
This avoids creating of a new object and copying overhead, but is it safe? When would you recommend it and when not?
Why wouldn't it be safe? Unless the function stores a pointer or reference to the shared_ptr after it returns, there is no danger. In Christ, Steven Watanabe
On Thu, Mar 19, 2009 at 12:17 PM, Steven Watanabe
anony wrote:
Is there some utility in passing shared_ptr's as references as here: void bla(boost::shared_ptr<T>& bla_ptr); This avoids creating of a new object and copying overhead, but is it safe? When would you recommend it and when not?
Why wouldn't it be safe? Unless the function stores a pointer or reference to the shared_ptr after it returns, there is no danger.
That's not really sufficient to be totally safe. Code like this could fail too: void do_work(some_shptr const & myobj) { std::cout << *myobj << '\n'; do_something(); std::cout << *myobj << '\n'; // oops (?) } Suppose that the shptr reference is invalidated in the call to do_something. This is entirely possible if the underlying object is owned by a global lookup table, and the caller of do_work() does not retain a reference to the object being passed in. When this happens, the global lookup table holds the only reference, and do_something might remove the element and invalidate the shptr.
From experience. :)
Chris
Hi!
On Thu, Mar 19, 2009 at 4:57 PM, anony
Is there some utility in passing shared_ptr's as references as here:
void bla(boost::shared_ptr<T>& bla_ptr);
Yes, boost::reference_wrapper. You might use it as follows: bla(boost::ref(bla_ptr));
This avoids creating of a new object and copying overhead, but is it safe? When would you recommend it and when not?
It depends on the calling context... If you can ensure, that the pointer reference is not stored and the calling function lives longer as the called function (might happen during asynchronous calls) it is safe. Otherwise it is not. Here an example: struct Bar { Bar() : data_() {} ~Bar() { *data_ = 100; } void set(shared_ptr<int> const& data) { data_ = data.get(); } private: int* data_; }; //possible misuse void foo() { Bar bar; shared_ptr<int> ptr = shared_ptr<int>(new int(10)); bar.set(ptr); } // BOOM!!! => ptr is destroyed before the Bar::~Bar() is called If you do not program real time soft, it is probably always better to copy sp. Ovanes
//possible misuse void foo() { Bar bar; shared_ptr<int> ptr = shared_ptr<int>(new int(10));
bar.set(ptr); } // BOOM!!! => ptr is destroyed before the Bar::~Bar() is called
If you do not program real time soft, it is probably always better to copy sp.
In your example, how would the behavior change, if Bar::set would take the pram by value?
Yes, that's true. This was coded to model what can happen.
Corrected example could be:
struct Bar
{
explicit Bar(shared_ptr<int> const& data)
: data_(data)
{}
~Bar()
{
*data_ = 100;
}
private:
shared_ptr<int> const& data_;
};
//possible misuse
void foo()
{
shared_ptr<int> ptr = shared_ptr<int>(new int(10));
Bar bar(ptr);
ptr.reset();
} // BOOM!!! => ptr is destroyed before the Bar::~Bar() is called
On Thu, Mar 19, 2009 at 5:34 PM, Igor R
//possible misuse void foo() { Bar bar; shared_ptr<int> ptr = shared_ptr<int>(new int(10));
bar.set(ptr); } // BOOM!!! => ptr is destroyed before the Bar::~Bar() is called
If you do not program real time soft, it is probably always better to copy sp.
In your example, how would the behavior change, if Bar::set would take the pram by value?
Corrected example could be:
struct Bar {
explicit Bar(shared_ptr<int> const& data) : data_(data) {}
~Bar() { *data_ = 100; }
private: shared_ptr<int> const& data_; };
//possible misuse void foo() { shared_ptr<int> ptr = shared_ptr<int>(new int(10)); Bar bar(ptr);
ptr.reset();
} // BOOM!!! => ptr is destroyed before the Bar::~Bar() is called
Well, the problem here is *storing* a reference - not a passing param by (const) reference.
Igor,
please take a look at my first post. I wrote there: if you can ensure that
the reference is not saved. This is an essential pitfall. If you pass a
value and bind it to a reference a good compiler will warn you that you are
binding a reference to a temporary object. If you pass the reference no
warnings are issued, but the app crash.
On Thu, Mar 19, 2009 at 6:13 PM, Igor R
Corrected example could be:
struct Bar {
explicit Bar(shared_ptr<int> const& data) : data_(data) {}
~Bar() { *data_ = 100; }
private: shared_ptr<int> const& data_; };
//possible misuse void foo() { shared_ptr<int> ptr = shared_ptr<int>(new int(10)); Bar bar(ptr);
ptr.reset();
} // BOOM!!! => ptr is destroyed before the Bar::~Bar() is called
Well, the problem here is *storing* a reference - not a passing param by (const) reference.
Is there some utility in passing shared_ptr's as references as here:
void bla(boost::shared_ptr<T>& bla_ptr);
This avoids creating of a new object and copying overhead, but is it safe? When would you recommend it and when not?
Passing object by reference means you want to modify it inside the function. If you only want to avoid overhead, pass it by const reference.
Igor R pravi:
Passing object by reference means you want to modify it inside the function. If you only want to avoid overhead, pass it by const reference.
Perhaps I do want to... Call reset() perhaps. Does boost::shared_ptr<> const& avoid overhead better than just boost::shared_ptr<T>&?
For boost::shared_ptr it's the same. Nothing is copied in both cases. Some
compilers might (which is under doubt) optimize it better. Since const is an
additional information for them, that the object is not going to change
within the called function.
const is definitely a benefit for you, since you can eliminate more errors
at compile time if you try to change the const object. I think a developer
should try to program as restrictive as possible, otherwise you might bring
unforeseen errors in your code. But that gets a bit philosophical.
On Thu, Mar 19, 2009 at 10:57 PM, anony
Igor R pravi:
Passing object by reference means you want to modify it inside the function. If you only want to avoid overhead, pass it by const reference.
Perhaps I do want to... Call reset() perhaps. Does boost::shared_ptr<> const& avoid overhead better than just boost::shared_ptr<T>&?
On Thu, Mar 19, 2009 at 3:49 PM, Ovanes Markarian
For boost::shared_ptr it's the same. Nothing is copied in both cases. Some compilers might (which is under doubt) optimize it better. Since const is an additional information for them, that the object is not going to change within the called function.
Const in a reference is merely part of the type safety system. Compilers can not do optimizations based on the constness of a reference, all they can do is report errors. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
What about RVO and NRVO?
You still can bind a temporary to a const reference. This is a simple
example on how it is possible to do optimizations. Or am I mistaken?
Example:
std::string foo();
void bar()
{
std::string const& bound_temporary = foo();
std::cout << bound_temporary;
}
whereas this is invalid:
void invalid_bar()
{
std::string& bound_temporary = foo(); //will not work, but AFAIK some
compilers support it
}
So compilers can do optimizations based on constness.
Regards,
Ovanes
On Fri, Mar 20, 2009 at 12:15 AM, Emil Dotchevski
On Thu, Mar 19, 2009 at 3:49 PM, Ovanes Markarian
wrote: For boost::shared_ptr it's the same. Nothing is copied in both cases. Some compilers might (which is under doubt) optimize it better. Since const is an additional information for them, that the object is not going to change within the called function.
Const in a reference is merely part of the type safety system. Compilers can not do optimizations based on the constness of a reference, all they can do is report errors.
Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
On Thu, Mar 19, 2009 at 4:29 PM, Ovanes Markarian
What about RVO and NRVO?
You still can bind a temporary to a const reference. This is a simple example on how it is possible to do optimizations. Or am I mistaken?
Example:
std::string foo();
void bar() { std::string const& bound_temporary = foo();
std::cout << bound_temporary; }
whereas this is invalid:
void invalid_bar() { std::string& bound_temporary = foo(); //will not work, but AFAIK some compilers support it }
Right, your first snippet is valid and the second is ill-formed.
So compilers can do optimizations based on constness.
What optimizations do you have in mind? The second snippet is simply illegal C++ (should not compile.) Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
Emil,
I know that the second snippet is illegal in C++, but your statement was
that const is only a part of type system and has no impact on optimization,
I just answered you with my doubts, and made a first obvious example with
NRVO, which highly depends on const.
const might also involve some optimizations, e.g. in multi-threaded context.
Let's imagine a value being passed to a function by const reference. This
function starts 2 or more threads and passes the value to them as reference
to a const object as well. What happens in this context? As long it is not
volatile it might be cached in a register, but I think that if the value is
const, compiler has stronger assumption, that this value is good enough to
be cached for all threads...
On Fri, Mar 20, 2009 at 1:56 AM, Emil Dotchevski
On Thu, Mar 19, 2009 at 4:29 PM, Ovanes Markarian
wrote: What about RVO and NRVO?
You still can bind a temporary to a const reference. This is a simple example on how it is possible to do optimizations. Or am I mistaken?
Example:
std::string foo();
void bar() { std::string const& bound_temporary = foo();
std::cout << bound_temporary; }
whereas this is invalid:
void invalid_bar() { std::string& bound_temporary = foo(); //will not work, but AFAIK some compilers support it }
Right, your first snippet is valid and the second is ill-formed.
So compilers can do optimizations based on constness.
What optimizations do you have in mind? The second snippet is simply illegal C++ (should not compile.)
Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
AMDG Ovanes Markarian wrote:
I know that the second snippet is illegal in C++, but your statement was that const is only a part of type system and has no impact on optimization, I just answered you with my doubts, and made a first obvious example with NRVO, which highly depends on const.
This is a case of programmer optimization rather than compiler optimization, though.
const might also involve some optimizations, e.g. in multi-threaded context. Let's imagine a value being passed to a function by const reference. This function starts 2 or more threads and passes the value to them as reference to a const object as well. What happens in this context? As long it is not volatile it might be cached in a register, but I think that if the value is const, compiler has stronger assumption, that this value is good enough to be cached for all threads...
If you have a reference to const, the compiler cannot make any assumptions about whether it is modified or not, because of const_cast. Objects declared const are another matter, because it is undefined behavior to modify them. In Christ, Steven Watanabe
On Fri, Mar 20, 2009 at 5:00 PM, Steven Watanabe
const might also involve some optimizations, e.g. in multi-threaded
context. Let's imagine a value being passed to a function by const reference. This function starts 2 or more threads and passes the value to them as reference to a const object as well. What happens in this context? As long it is not volatile it might be cached in a register, but I think that if the value is const, compiler has stronger assumption, that this value is good enough to be cached for all threads...
If you have a reference to const, the compiler cannot make any assumptions about whether it is modified or not, because of const_cast. Objects declared const are another matter, because it is undefined behavior to modify them.
Ok, I don't want to stick on this. In my initial post, I wrote that const provides a compiler an additional information which !!!might!!! be used usefully for optimization (!!!big doubt!!!). Emil writes that this info for sure is neglected, but I still don't think so. Greetings, Ovanes
AMDG Ovanes Markarian wrote:
On Fri, Mar 20, 2009 at 5:00 PM, Steven Watanabe
wrote: If you have a reference to const, the compiler cannot make any assumptions about whether it is modified or not, because of const_cast. Objects declared const are another matter, because it is undefined behavior to modify them.
Ok, I don't want to stick on this. In my initial post, I wrote that const provides a compiler an additional information which !!!might!!! be used usefully for optimization (!!!big doubt!!!). Emil writes that this info for sure is neglected, but I still don't think so.
It is theoretically possible for the compiler to use the const to optimize, but to do so it would have to prove that the functions which are called a) do not use a non-const reference to the same object. b) do not cast away the const. (a) is independent of the presence or absence of const. Determining (b) is not very different from determining from scratch whether a variable is modified. In Christ, Steven Watanabe
On Fri, Mar 20, 2009 at 2:18 PM, Steven Watanabe
AMDG
Ovanes Markarian wrote:
On Fri, Mar 20, 2009 at 5:00 PM, Steven Watanabe
wrote: If you have a reference to const, the compiler cannot make any assumptions about whether it is modified or not, because of const_cast. Objects declared const are another matter, because it is undefined behavior to modify them.
Ok, I don't want to stick on this. In my initial post, I wrote that const provides a compiler an additional information which !!!might!!! be used usefully for optimization (!!!big doubt!!!). Emil writes that this info for sure is neglected, but I still don't think so.
It is theoretically possible for the compiler to use the const to optimize, but to do so it would have to prove that the functions which are called a) do not use a non-const reference to the same object. b) do not cast away the const.
Since b) is a subset of a), only a) needs to be proven. But const *can not* possibly help prove a).
(a) is independent of the presence or absence of const. Determining (b) is not very different from determining from scratch whether a variable is modified.
Exactly. Therefore, const in references does *not* provide anything the compiler can use for optimization purposes. If we're talking about an actual object, not a reference, that's a different story altogether. Since we keep discussing this, I went ahead and explained it all here: http://www.revergestudios.com/reblog/index.php?n=ReCode.Const. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode
participants (6)
-
anony
-
Chris Uzdavinis
-
Emil Dotchevski
-
Igor R
-
Ovanes Markarian
-
Steven Watanabe