Is it safe to remove the only shared_ptr reference to itself inside a method? Something like the following. If two objects, one of class A and the other of class B, points to each other via their pB_ and pA_. Suppose pB_ is the only reference to the object of class B. Then I call A::method() on the object of class A. Will there be any problem?
#include <iostream>
using std::shared_ptr
class B;
class A {
public:
void method() {
pB_->method();
}
shared_ptr<B> pB_;
};
class B {
public:
void method() {
pA_->pB_.reset();
// Is this OK? And is it safe if I don't do this?
some_other_data_ = 10;
}
shared_ptr<A> pA_;
int some_other_data_;
};
Resetting that pointer will result in the B object being deleted, so no, it is not okay to access one of its members after that point. For more info, see: Is it safe to `delete this`?
Related
in below scenario, I need to invoke child class B function (fun1) from Base class A shared pointer
returned by setup function and for the same have used dynamic_cast_pointer so that derived
class shared_ptr object can be assigned to Base class shared_ptr but during compilation I am
not allowed to do so. Can anybody suggest how to achieve this behaviour
#include <iostream>
#include <memory>
using namespace std;
class A
{
public:
void fun() {cout<<"A"<<endl;}
};
class B : public A
{
public:
void fun1() {cout<<"B" <<endl;}
};
shared_ptr<A> setup(shared_ptr<A> ptr = nullptr )
{
if(!ptr)
{
ptr = make_shared<A> ();
}
ptr.get()->fun();
return ptr;
}
int main() {
auto ptr = std::dynamic_pointer_cast <B> (setup());
ptr->fun1(); // Doesn't compile
}
I presume the question is cut down from the real problem.
Presuming you're not expecting this example to work at runtime (you are casting a pointer to A as a pointer to B when it's an instance of A - so you're in undefined behaviour territory), the issue is that you have no virtual methods. The compiler tells you this:
error: 'A' is not polymorphic
When you intend to use pointers to a base class, you need to have virtual destructors (personally I always use them as a matter of course).
See demo: https://godbolt.org/z/qe6jPrhsa
Here you can see a modified example demonstrating that you're in Undefined Behaviour territory...
https://godbolt.org/z/harzoP946
I have a problem. I'd like to point shared_ptrs to objects that are stored in a class. In the code there is a Holder::getSomething() function that returns a reference to a base. I'd like to cast that to the derived b_ptr. Here's the code:
#include <memory>
using namespace std;
class A{
public:
int a;
A() : a(0){}
virtual ~A(){}
};
class B : public A {
public:
bool b;
B() : A(){ b = false; }
};
class Holder{
public:
B arr[1];
// there's an A ref here, not B, because i'll have a boatload of deriveds.
A& getSomething(){
return arr[0];
}
Holder(){
arr[0] = B();
}
};
int main(){
Holder h;
shared_ptr<B> b_ptr;
// b_ptr = something_alien_here(h.getSomething());
return 0;
};
I know ( and by "know" i mean i have an uneducated guess ) that i should use dynamic_(pointer_?)cast but i cant find/figure out the right syntax.
The whole point of a shared pointer is that its ref counted, and destructs
what it points to when the last one go out of scope. You don't want that to happen
to a member object of another class, since that is undefined behaviour.
in short; don't do that.
If you can guarantee that h will live longer than b_ptr, then you can use the borrowing constructor of shared_ptr, together with a cast:
Holder h;
std::shared_ptr<B> b_ptr(std::shared_ptr<B>(),
&static_cast<B&>(h.getSomething()));
Now b_ptr shares ownership with the temporary, empty shared pointer, which has the effect of never calling the deleter for B. This is why it is now your responsibility to guarantee that the pointee exists for at least as long as the shared pointer may be dereferenced.
I have two classes, for instance, A and B. I would like to pass A as reference to B.
class I
{
public:
virtual void callback() = 0;
};
class B
{
public:
B(I* callback) : _callback(callback) {}
private:
I* _callback;
};
class A : public I
{
public:
A() : _b(new B(this)) {}
private:
B* _b;
};
And I would like to:
get rid of naked pointers (for instance, with a help of std::shared_ptr and std::weak_ptr).
avoid cyclic referencing.
But there are some problems:
How do I create a weak pointer INSIDE a class A? First, I should be sure that an instance of A is managed by some shared_ptr. Even if I'm really sure, how can I find this shared_ptr instance?
Generally, how can I ensure that I'm using instances of some class ONLY via shared pointers? I can try to create factory method and make constructor private, but it leads to error: make_shared demands a public contstructor.
Thanks in advance!
EDIT:
More detail explanation of problem: I have a class A. This class wants to pass some part of work to a class B. So I have a shared pointer to B inside A. And I would like B to do this asynchronously, and B should call A's callback when there is some progress or when the work is done. So B should have a reference to A.
class I
{
public:
virtual void isDone() = 0;
};
class B
{
public:
B(I* callback) : _callback(callback) //how do I take and store callback inside B???
{
//async invocation of run()
}
private:
weak_ptr<I> _callback;
void run()
{
if(_callback.get())
{
_callback->isDone();
}
}
};
class A : public I
{
public:
A() : _b(new B(this)) {} //how do I pass this to B???
private:
shared_ptr<B> _b;
virtual void isDone()
{
cout << "job is complete" << '\n';
}
};
So the question is: how do I pass A to B? I can try to do it via naked pointer or reference, but it's safety because B has no guarantees that this referenced object is still alive (common problem of all naked pointers). So I would like to pass a weak pointer, and my question was all about it.
The first problem can be solved with std::enable_shared_from_this, which allows you to safely create a shared pointer instance from within class A.
The second problem may be solved by using a static factory method belonging to class A and not using std::make_shared like this:
static std::shared_ptr<A> create() {
return std::shared_ptr<A>(new A());
}
Then, you can make A's constructor private.
I have the following situation:
class B
{
public:
void methodInB();
};
class C
{
public:
void methodInC();
};
class A
{
public:
void methodInA();
private:
B objB;
C objC;
};
void A::methodInA()
{
objB.methodInB();
}
int main()
{
A objA;
objA.methodInA();
return 0;
}
I want to be able to call C::methodInC() from within B::methodInB(), but I'm not sure what the way to go about it would be (not without messing with globals).
My first idea was to add a C* pC pointer as a member of B, and then from methodInB() call it as pC->methodInC. This would require I set the pointer from within A before using the method (possibly in A's constructor). My problem is I may need to call other objects from within B if I add a D and E objects, and I don't want to fill the class definition with pointers.
Is there some other way of doing this? An implicit reference to the object the object belongs to? Kind of like this but for the parent? So I could at least do parent->objC->methodInC()?
I think the cleanest way would be to "inject the dependency", that is, to pass objC to methodInB, which would then invoke methodInC on that object:
void A::methodInA()
{
objB.methodInB(objC);
}
// ...
void B::methodInB(C &objC)
{
objC.methodInC();
}
Let every class B, C, D, E, etc. have a pointer to the A object of which they are subobjects.
class A;
class C;
class B
{
A* pA;
void MethodB();
};
...
void B::MethodB
{
(pa->CObject).MethodC();
}
I have the code:
class A{ //base class
public:
virtual std::string getString(){return "class A";}
};
class B: public A{
public:
std::string getString() {return "it is B class";}
};
class C{
public:
C(){
B b;
a = b;
}
std::string test() {return a.getString();}
private:
A a;
};
int main()
{
C c;
std::cout << c.test();
return 0;
}
c.test() says "class A", but how I can call method getString() from class B and not A?
Thanks!
The problem is, your B object gets sliced when assigned to an A object. This is because you assigned by value, not by reference or pointer. Since you declared a like this
A a;
what happens during the assignment a = b is that the actual state of b is copied over into a. However, since a is a value object, only the A part of object b is copied, and its "B-ness" is completely lost!
To avoid this, you need to declare a as a pointer type, as suggested by others (a reference would also work, but then you would need to considerably rewrite your example, since you can't assign to references, only initialize them). If a is a pointer (A*), the assignment a = b makes a point to the object represented by b, which is still a B object, thus you will observe the polymorphic behaviour you expected. However, in this case, you must ensure that b stays alive even after exiting the constructor - otherwise you leave a dangling reference which causes undefined behaviour (read: bad things you don't want to happen) when dereferenced.
Since a pointer example was already shown by #Nawaz, I will give another using a reference:
class C{
public:
C() : a(b) { // references must be initialized in the constructor initializer list
}
std::string test() {return a.getString();}
private:
B b; // moved to class scope to ensure that it stays alive
A& a;
};
You need to implement like this:
class C{
public:
C(){
a = new B;
}
std::string test() {return a->getString();}
private:
A *a;
};
This will call getString() from class B and not A.
What you're trying to do is called "dynamic polymorphism" which is achieved through pointer (or reference) of type base class (which is A), but the pointer points to an object of type derived class (which is B).
Because your member a is not an A*, it is an A instance. Therefore you are just assigning the A part of B to variable a. if you convert a to an A*, you will get the expected result.
You are slicing therefore it will not work. a is an A it is not a B.
To work your class member variable a must be a pointer or a reference.
As a pointer
class C{
public:
C(){
a = new B;
}
std::string test() {return a->getString();}
private:
A *a;
};
As a reference
class C{
public:
C() : a( *(new B) )
{
}
std::string test() {return a.getString();}
private:
A &a;
};
Of course the code I have produced leaks but will work with the virtual function.