Get shared_ptr by reference with dynamic_pointer_cast - c++

Is it ok to get the return value from dynamic_pointer_cast by reference, or can it cause problem?
struct A
{
};
struct B : public A
{
};
int main()
{
shared_ptr<A> b = make_shared<B>();
auto &a = dynamic_pointer_cast<A>(b);
//auto a = dynamic_pointer_cast<A>(b);
return 0;
}

Even if it were possible, it wouldn’t do what you want:
[The aim is that] the reference counter is not increased
It would still be increased since dynamic_pointer_cast returns a new shared_ptr copy anyway.
Your code doesn’t work since the reference would then be bound to the temporary object returned by the dyanamic_pointer_cast and this is forbidden.
Using a const reference would work (since const& is allowed to bind to a temporary) but the result would still be the same: the cast would create a new instance of a shared_ptr, and increment the reference count.

Related

Getting raw ptr from a shared_ptr and make it shared again

Why the code below do not works?
class A {};
void f(A* a) {
shared_ptr<A> c(a);
}
int main() {
auto a = make_shared<A>();
auto b = a.get();
f(b);
return 0;
}
In the end of the scope of f, my program crashes. What could be causing this? Is there something that's trying to be deleted and does not exists?
You have two unrelated shared pointers that are both trying to manage the same resource. That leads to undefined behaviour. In particular, they're both going to try to delete the resource when they go out of scope.
In general, just don't do this :)
class A {};
void f(A* a) {
shared_ptr<A> c(a);
}
int main() {
auto a = make_shared<A>();
auto b = a.get();
f(b);
return 0;
}
What's happening here is that your initial make_shared() is creating a shared_ptr which owns A. When you call f(b), you are creating a second, unrelated shared pointer which also thinks it owns the same data. When the function call f() ends, the local shared ptr variable is destroyed; this checks whether the reference count is zero (which it will be), and so deletes the object. Then, when the main function ends, the destructor for the local variable a runs, checks that the reference count is zero (again, it will be), and so tries to delete the same data a second time. This double-delete is what is causing the crash.
There are a couple of solutions to this: the easiest is simply not to deal with raw pointers, and pass the shared_ptr directly to f(). Then the reference counting will work correctly and the data will only be destroyed once.
Another way of doing this is to have your class A publicly inherit from std::enable_shared_from_this. Then you can use the shared_from_this() method to "recover" a shared pointer (with correct reference counting) from a raw pointer, i.e.
class A : public std::enable_shared_from_this<A> {};
void f(A* a) {
shared_ptr<A> c = a->shared_from_this();
}
You can read about enable_shared_from_this here.

How do constant references work?

Recently I have been learning about good programming practice in C++ and found out that many programs pass objects to functions by reference so that multiple instances are not created. I have also learned that passing a constant reference prevents the original object from being modified however I do not understand how this works exactly. Shouldn't a constant reference create a new instance because the original object cannot be modified through the reference but the reference can still be used like a separate object? I'm fairly certain that this is not how it works but then, how does it work? Is there something I missed?
I have also learned that passing a constant reference prevents the original object from being modified [...]
Not quite. You are not allowed to modify the object through the const &. In other words, you have read-only access. But nothing natively prevents other code with read-write access (for example the original owner of the referred object) to modify it. You do need to be careful when designing so that such changes do not surprise you.
A constant reference (const&) is similar to a pointer to a constant object. You are allowed to read it through the reference but not modify it. Others, holding a non-const reference can still modify it.
Shouldn't a constant reference create a new instance because the
original object cannot be modified through the reference but the
reference can still be used like a separate object?
It's better to call it a reference to a constant object. This makes it much clearer how the thing works. Calling it the other way around is just confusing because any reference is constant (meaning you can't let it refer to another object after initialization).
So a reference to a constant object is just an additional name for an existing object (like a non-const reference) with the restriction that this name only allows reading from the existing object.
This means that through a reference to a constant object you can:
only read from member variables of the object, but not assign to them, unless a member is marked as mutable
only call methods of the object that are marked as const
Example:
struct Foo
{
int a;
mutable int b;
void SetA( int newA ) { a = newA; }
int GetA() const { return a; }
};
void DoSomething( const Foo& f )
{
// Here, f is just another name for foo, but it imposes some restrictions:
f.a = 42; // compiler error, can't modify member!
f.SetA( 42 ); // compiler error, can't call non-const method!
int x = f.a; // OK, reading is allowed.
f.b = 42; // OK, because b is marked as mutable
int y = f.GetA(); // OK, because GetA() is marked as const
}
int main()
{
Foo foo;
DoSomething( foo );
}

Create aliases to boost::shared_ptr via reference

I have a small segment of code that I need to optimize. Thread 'A' has created a boost shared_ptr to a heap object. Thread 'A' writes the shared_ptr to a thread safe queue. Thread 'B' reads the shared_ptr, uses it, and then destroys it.
Intense profiling/testing proves that the copying of the shared_ptr going in/out of the queue and adjusting reference counts is costly. Therefore, I would like to pass the shared ptr to the queue via reference. I would also like to use std::move to move the shared_ptr into the queue rather than construct a new shared_ptr, (I know this will invalidate the shared_ptr parameter which was passed to the queue).
Everything described works fine until I mix in a dash of polymorphism. I can't pass by ref a shared_ptr to a derived obj to a function expecting a shared_ptr to a base class. I have boiled this down to a very small snip that exposes the behavior that confuses me.
#include <boost/shared_ptr.hpp>
class Base
{
};
class Derived : public Base
{
};
int main()
{
boost::shared_ptr<Derived> pDerived(new Derived()); // simple creation
boost::shared_ptr<Derived> &alias1 = pDerived; // works fine
const boost::shared_ptr<Base> &alias2 = pDerived; // also works fine
boost::shared_ptr<Base> &alias3 = pDerived; // compilation error
//native pointers
Derived *alias4 = pDerived.get(); //works
const Base *alias5 = pDerived.get(); //works
Base *alias6 = pDerived.get(); //works
//native references
Derived &alias7 = *pDerived; // works
const Base &alias8 = *pDerived; // works
Base &alias9 = *pDerived; // works
}
I do not understand why the assignment to alias2 is perfectly fine, yet the assignment to alias3 yields a compiler error. Can someone please explain this? I need functionality like the alias3 example and can't make it work.
This problem is not related to boost or smart pointers. It can happen with POD types too as shown in the following simple example:
int main() {
int x = 0;
const double &y = x; //fine
double &z = x; //error!
return 0;
}
The reason is that a temporary value (rvalue) can bind to a const& but it cannot bind to a &. What happens in double &z = x is that x and z are unrelated types, and x needs to be converted to a double and a temporary variable is created, which cannot bind to a &.

Obtaining object from function by reference instead by value

I wonder if code below is correct - it works in this case but it may be just because of its simplicity. What makes me wonder: function (f1) returns object by value but in function which called it (f2) I obtain this object by reference not by value. Is this a problem? I wonder because it looks a bit weird to me but it works and i think it should works. Because object is created on the stack of f1 and then returned (by value) to stack f2 and after that a reference is obtained to this object on f2 stack which was created on f1 stack. What do you think about this?
class A {
public:
A(){a=100; b=200;}
int a;
int b;
};
typedef boost::shared_ptr<A> AP;
AP get(){
AP a = AP(new A());
return a;
}
AP get2(){
AP const& a = get();
return a;
}
int main() {
AP const& a = get2();
std::cerr << a->a << std::endl;
return 0;
}
It's weird, but safe.
Binding a temporary object to a reference extends its lifetime to that of the reference; so what you're doing is equivalent to creating a local object variable. The use of a reference adds obfuscation, requiring the reader to know these odd rules to understand what's happening, but doesn't change the program's validity or behaviour.
In the both cases
AP const& a = get();
and
AP const& a = get2();
You bind a temporary object with a const reference. The object will be alive while there will be alive the reference. So there is no problem with your code.

Binding rvalue-reference to a local variable in VC++

I'm using VC++2012 to run the following code:
#include <utility>
struct A
{
int* m_p;
A() { m_p = new int; }
~A() { delete m_p; }
A(const A& otherA)
{
m_p = new int;
// BOOM!
*m_p = *otherA.m_p;
}
};
A&& CreateA()
{
A a;
return std::move(a);
}
int _tmain(int argc, _TCHAR* argv[])
{
A a2 = CreateA();
return 0;
}
During the creation of a2 A's copy ctor is called - and crashes, since the source object created in CreateA() is already destroyed.
Is this standard behaviour? Could this be a compiler bug??
Notice that if you change a2's type from 'A' to 'const A&' the crash doesn't occur - which reinforces the suspicion that it is indeed a bug.
Can anyone shed some light on this?
Note: I'm fully aware this is not the intended usage for rvalue-refs, and this example is contrived. Just hoping to get a better grasp on the behaviour of this new type.
Look at what happens in your code:
CreateA() is called
inside the function, a local variable of type A is created.
you create a rvalue reference pointing to this local variable
you return this rvalue reference
as you return, the object of type A, which the rvalue reference points to, goes out of scope, and gets destroyed
the reference now points to a destroyed object
you try to initialize a2 as a copy of the object that once existed inside the function call
And... that doesn't work. The object you're trying to copy is dead and gone. Undefined behavior.
Don't do that. :)
In C++, references do not affect the lifetime of the referenced object. There is no "I'm pointing at this object, so you can't destroy it!".
Never return references to local objects. It doesn't work, so... just don't do it.
You cannot access a local variable outside its scope. Rvalue references don't change that: they are still references. The code presented has undefined behaviour because it returns a reference to a local variable and then accesses it.
Don't return rvalue references. That is silly the vast majority of time. Return values instead:
A CreateA()
{
A a;
return a; // a move here is automatic
// unless you are using a compiler with outdated rules like MSVC
//return std::move(a); // ok, poor MSVC
// alternatively:
//return A{}; //or
//return A();
}
When you write A const& a2 = CreateA(); nothing crashes, because you don't actually access any object. All you do is grab a dangling reference. However, this code is not even well-formed, it just happens to compile because MSVC has some outdate rules for reference binding.
So, basically, these behaviours are a mix of compiler bugs and undefined behaviour :)