Lifetime of dependent classses in C++? - c++

I have a class A that provides methods to construct instances of class B. And B holds a private reference to A and provides a constructor to set this reference.
class A {
public:
B* construct_B ();
}
class B {
private:
const A& private_A;
public:
B ( const A& my_A ): private_A (my_A) { }
}
The implementation of construct_B takes care of dynamic allocation and passing the reference to itself via this.
How do I implement this setup in such a way that I make sure that the lifetime of A is longer than B so that its reference remains valid? Notice that I don't care about all the possibilities of construct_B instead of returning a raw pointer I could return a smart pointer or similar.
One possible way of solving this could be having B instead of holding a reference to hold a smart pointer to A, and instead of dynamically allocating B in construct_B to take a static reference to B and then set it's pointer, something like
class A :
public std::enable_shared_from_this<A> {
public:
void setup_B ( const B& my_B ) {
my_B.set_A (shared_ptr_from_this() ) ;
}
class B {
private:
const shared_ptr<A> private_A_ptr;
public:
void set_A ( const shared_ptr<A> my_A ):
private_A_ptr (my_A) { }
}
which then could be implemented by
int main () {
A static_A;
B static_B;
A.setup_B (static_B);
}
Does the shared_ptr of this last construction avoid the problem of A being deleted before B?

shared_ptr is your answer. Something like this:
#include <memory>
struct A;
class B {
const std::shared_ptr<A> private_A_ptr;
public:
B(std::shared_ptr<A> parent) : private_A_ptr(std::move(parent)) {}
};
struct A :
std::enable_shared_from_this<A>
{
B make_b() {
return B(shared_from_this());
}
};
int main()
{
// this would be invalid:
//A a;
//auto b = a.make_b();
// but this is fine
auto pa = std::make_shared<A>();
auto b = pa->make_b();
// later...
pa.reset();
// A still exists because ownership was shared with b
}

Related

Alternatives for storing a class member as a raw pointer

In the code example shown below - in Container class, it owns (and is responsible fore destroying) two objects c, d, which are subclasses of an abstract class B. Container object can create new ObjectDisplay that takes a kind of B in its constructor. I can pass the abstract type B as a pointer into ObjectDisplay and store it as a RAW pointer. But it's not ideal to store & use a raw pointer and always check if it's a null pointer. If B wasn't an abstract class, I could pass it in ObjectDisplay as a reference (ie. ObjectDisplay (B& b)). But since I can't change B, I wonder what's the aternative of storing B* object as a raw pointer in ObjectDisplay?
// B is abstract
class B
{
public:
virtual int getDefault() = 0;
};
class C : public B
{
public:
int getDefault() override { return 1; }
};
class D : public B
{
public:
int getDefault() override { return 5; }
};
class ObjectDisplay
{
public:
ObjectDisplay (B* b) : object (b) {}
void someFunction()
{
const auto result = b->getDefault();
// do something
}
private:
B* object;
};
class Container
{
public:
void addDisplay()
{
displays.push_back (ObjectDisplay (&c));
displays.push_back (ObjectDisplay (&d));
}
private:
C c;
D d;
std::vector<ObjectDisplay> displays;
};
If B wasn't an abstract class, I could pass it in ObjectDisplay as a reference
No, if B is an abstract class, you can still pass it by reference. B& object can be bound to an instance of B's subclass. It behaves almost the same as pointers.
As quoted in cppref:
That is to say, if a derived class is handled using pointer or reference to the base class, a call to an overridden virtual function would invoke the behavior defined in the derived class.
Declare a member of B& in ObjectDisplay and construct it through a reference.
class ObjectDisplay
{
public:
ObjectDisplay (B& b) : object (b) {}
private:
B& object;
};
class Container
{
public:
void addDisplay()
{
displays.push_back (ObjectDisplay (c));
displays.push_back (ObjectDisplay (d));
}
};
See online demo
Aside:
Since you are passing a temporary ObjectDisplay object directly constructed in push_back, I recommend you to use emplace_back.
void addDisplay()
{
displays.emplace_back (c);
displays.emplace_back (d);
}
If B wasn't an abstract class, I could pass it in ObjectDisplay as a reference (ie. ObjectDisplay (B& b)). But since I can't change B, I wonder what's the aternative of storing B* object as a raw pointer in ObjectDisplay?
Just because B is an abstract class does not mean you are required to pass it around and store it as a pointer. You CAN pass it around and store it as a reference as well. Polymorphism works with pointers AND references. And using a reference would indeed solve your nullptr issue, eg:
class ObjectDisplay
{
public:
ObjectDisplay (B& b) : object (b) {}
void someFunction()
{
const auto result = object.getDefault();
// do something
}
private:
B& object;
};
class Container
{
public:
void addDisplay()
{
displays.push_back (ObjectDisplay (c));
displays.push_back (ObjectDisplay (d));
}
private:
C c;
D d;
std::vector<ObjectDisplay> displays;
};
Online Demo
As long as c and d outlive the ObjectDisplay objects in displays, you will be just fine, whether you use pointers or references.

C++ shared_ptr, how can i return reference to an object from shared pointer created inside a method?

i am new to shared pointers. I would like to have a method which returns reference to an object. The object will be created inside a method by make_shared and also stored in a vector as a shared pointer of base class. I guess my code is not the best way to do it. Any suggestions?
Thank you.
class A {
public:
};
class B : public A {
public:
};
class Factory {
public:
B& createA() {
std::shared_ptr<B> b = std::make_shared<B>();
container.push_back(b);
return *b;
}
private:
std::vector<std::shared_ptr<A>> container;
};
int main() {
Factory factory;
B& b = factory.createA();
// work with B here...
}

Using smart pointers to keep track of data members that may be deleted

I have two classes A and B. I compute a B deterministically from an A. For each A, I want to keep track of the B with my_B for as long as it exists. Once the B is destructed, I want the my_B to be changed to something like nullptr.
class A{
// stuff
public:
B ComputeB(){
if (my_B is null){
B result = B(A);
my_B = B; // some kind of reference
return B(A);
}
else {
return my_B;
}
}
~A(){ /* Do I need a destructor? */ }
private:
WhatTypeHere my_B;
}
When B is destructed, what will cause my_B to refer to nullptr (or the equivalent for WhatTypeHere)?
Using shared_ptr and weak_ptr
In order to keep your B object alive in A as long as it is still in use, you should have a data member in A of type std::weak_ptr<B> this will allow to access the created B object, as long as it is alive.
The return value from computeB would be std::shared_ptr<B> that would be either acquired from the std::weak_ptr<B> member or created, if the latter is holding nullptr.
Thread safety
The decision whether to create or acquire the existing B shall be thread-safe. For this you shall try to fetch the actual B held by the weak_ptr by using the lock() method, then only if the return value is nullptr create a new one.
The code would look like this:
class A {
// stuff
public:
std::shared_ptr<B> ComputeB() {
std::shared_ptr<B> shared_b = my_B.lock();
if (!shared_b){
shared_b = std::make_shared<B>(*this);
my_B = shared_b;
}
return shared_b;
}
// no need for a destructor, unless "stuff" needs one
// ~A(){}
private:
std::weak_ptr<B> my_B;
};
Copy and assignment
The behavior of above class in copying and assignment is problematic, as the default copy constructor and default assignment operator would perform member-wise copy/assignment, which may result with two different A's holding a weak_ptr to the same B. Most probably this is not what you want, especially not if A is mutable (i.e. can change its inner values).
To present suggested code for copy and assignment, let's assume A holds an int member. The code would then look like this:
class A {
int i;
public:
A(int i1): i(i1) {}
void set(int i1) { i = i1; }
std::shared_ptr<B> ComputeB() {
std::shared_ptr<B> shared_b = my_B.lock();
if (!shared_b){
shared_b = std::make_shared<B>(*this);
my_B = shared_b;
}
return shared_b;
}
A(const A& a): i(a.i) {}
A& operator=(const A& a) { i = a.i; return *this; }
~A() {}
private:
std::weak_ptr<B> my_B;
};
Preserving constness
In the code above, the call to ComputeB() cannot be done on a const A object. If we want to support that we need to have a const version of this function. For matter of semantics I prefer renaming this method (both the const and non-const versions) to getB.
To present suggested code that adds the option for calling getB on a const A object we need to present also an example of class B which is able to hold either a const or non-const reference to A. The code would then look like this:
class A {
int i;
// to prevent code duplication for the const and non-const versions
template<typename AType>
static auto getB(AType&& a) {
std::shared_ptr<B> shared_b = a.my_B.lock();
if (!shared_b){
shared_b = std::make_shared<B>(std::forward<AType>(a));
a.my_B = shared_b;
}
return shared_b;
}
public:
A(int i1): i(i1) {}
void set(int i1) { i = i1; }
std::shared_ptr<B> getB() {
return getB(*this);
}
std::shared_ptr<const B> getB() const {
return getB(*this);
}
A(const A& a): i(a.i) {}
A& operator=(const A& a) { i = a.i; return *this; }
~A() {}
private:
mutable std::weak_ptr<B> my_B;
};
And for B:
class B {
union Owner {
A* const ptr;
const A* const const_ptr;
Owner(A& a): ptr(&a) {}
Owner(const A& a): const_ptr(&a) {}
} owner;
public:
B(A& a): owner(a) {}
B(const A& a): owner(a) {}
const A& getOwner() const {
return *owner.const_ptr;
}
A& getOwner() {
return *owner.ptr;
}
};
On the use of union to manage const and non-const versions of the same pointer, see:
Union of const/non-const Object Pointers
Is const-casting via a union undefined behaviour?
Working example: http://coliru.stacked-crooked.com/a/f696dfcf85890977
Private creation token
The code above allows anybody to create objects of B which may lead to undesired possibilities, like creating a non-const B object via the constructor that gets const A& a, resulting with a potential casting from const to non-const when calling getOwner().
A good solution might be to block the creation of B and allow it only from class A. Since the creation is done via make_shared putting B's constructors in the private section of B with a friend declaration for A wouldn't help, it is not A that is calling new B it is make_shared. So we go for a private token approach as in the following code:
class A {
int i;
// only authorized entities can create B
class B_PrivateCreationToken {};
friend class B;
template<typename AType>
static auto getB(AType&& a) {
std::shared_ptr<B> shared_b = a.my_B.lock();
if (!shared_b){
shared_b = std::make_shared<B> (
std::forward<AType>(a),
B_PrivateCreationToken{} );
a.my_B = shared_b;
}
return shared_b;
}
public:
// public part as in above version...
private:
mutable std::weak_ptr<B> my_B;
};
And for B:
class B {
union Owner {
A* const ptr;
const A* const const_ptr;
Owner(A& a): ptr(&a) {}
Owner(const A& a): const_ptr(&a) {}
} owner;
public:
B(A& a, A::B_PrivateCreationToken): owner(a) {}
B(const A& a, A::B_PrivateCreationToken): owner(a) {}
// getOwner methods as in above version...
};
Code: http://coliru.stacked-crooked.com/a/f656a3992d666e1e
You can return a std::shared_ptr from ComputeB(), and make my_B a std::weak_ptr. Something like this:
std::shared_ptr<B> ComputeB() {
if (my_B.expired()) {
auto result = std::make_shared<B>(*this);
my_B = result;
return result;
} else {
return std::shared_ptr<B>(my_B);
}
}
private:
std::weak_ptr<B> my_B;
The idea is that any caller of ComputeB becomes the partial owner of the B instance, which means that it will only be destroyed when all shared_ptrs to it are destroyed. The purpose of the weak_ptr is to point to the B instance without owning it, so the lifetime isn't tied to the A instance at all

Initialize a class object with the this pointer in C++

In C++, I want to initialize (or change) a class object using the result of another class' method. Can I use the this pointer? Is there a better way?
Dummy example:
class c_A {
public:
int a, b;
void import(void);
};
class c_B {
public:
c_A create(void);
};
void c_A::import(void) {
c_B B;
*this = B.create();
};
c_A c_B::create(void) {
c_A A;
A.a = A.b = 0;
return A;
};
There is no problem. The member function void import(void); is not a constant function.In this statement
*this = B.create();
there is used the default copy assignment operator.
Is there a better way?
A better way is not to use a member function and just use an assignment statement for objects of the class as for example
c_A c1 = { 10, 20 };
c1 = c_B().create();

Informing the referencing object that the referred one is deleted in C++

I would like to ask the following:
Suppose that we have three classes in C++: A, B and C. An object of class A is creating and owning an object of class B. It is then giving the reference of B to an object of class C to be stored as a pointer variable. So, what is the best practice to inform C, that the pointer to B is no longer valid (and should be set to null), if A is deleted?
Is there a general approach or for example a Qt specific one?
Use std::weak_ptr
Example (live demo here)
class A
{
private:
std::shared_ptr<B> myB;
public:
A() :
myB(std::make_shared<B>())
{
}
std::weak_ptr<B> GetB()
{
return myB;
}
};
class B
{
};
class C
{
private:
std::weak_ptr<B> theB;
public:
C(std::weak_ptr<B> b) :
theB(b)
{
}
void test()
{
auto b = theB.lock();
if (b)
{
// theB is still valid
}
else
{
// theB is gone
}
}
};