Say that I have a class A and a class B which further has a subclass B1. Now I want to assign a pointer of B1 to be a member of A. I could do that by simply heap allocating B1 and then using delete in the destructor of A as follows:
class B {
public:
B() { };
};
class B1 : public B {
public:
B1() { };
};
class A {
public:
B* b_instance;
A(B* b_instance){
this->b_instance = b_instance;
};
~A(){
delete this->b_instance;
};
};
int main() {
B* b_instance = new B1();
A a_instance(b_instance);
return 0;
};
Now I believe another approach (and one that is more favored?) would use std::unique_ptr, whereby a unique_ptr to B1 is given to A and thus, as a smart pointer, whenever A is destroyed B1 is automatically destroyed as well since there are no more references to it. My best guess is that it should look something like this:
#include <memory>
class B {
public:
B() { };
};
class B1 : public B {
public:
B1() { };
};
class A {
public:
std::unique_ptr<B> b_instance;
A(B& b_instance){
this->b_instance = std::make_unique<B>(b_instance);
};
~A(){ };
};
int main() {
B1 b_instance;
A a_instance(b_instance);
return 0;
};
Is the unique_ptr approach the same as the approach outlined above so long as you remember to include delete this->b_instance in the destructor of A? Or are there other benefits of the unique_ptr approach?
Is the unique_ptr approach the same as the approach outlined above so long as you remember to include delete this->b_instance in the destructor of A?
More or less.
Or are there other benefits of the unique_ptr approach?
Yes, you get automatic move semantics and copy semantics is turned off, greatly helping to prevent involuntary multiple owners of the same resource.
Related
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...
}
In the below example I want to be able to access vector cList in class B in the function ShareData. How do I do that?
I have written a sample code. It fails to compile (Error message: B has no constructors). Even if it did, does the line cObj = new B(*this); introduce any circular dependency?
#include "stdafx.h"
#include <vector>
class B;
class A
{
public:
B* cObj;
std::vector<B*> cList;
A()
{
cObj = new B(*this);
}
};
class B
{
public:
B(A& aObj) : aObjLocal(aObj) {};
void ShareData(int result)
{
for (auto& iterator : aObjLocal.cList)
{
(*iterator).ShareData(result);
}
}
private:
A& aObjLocal;
};
void main()
{
A aMain;
B bMain(aMain);
bMain.ShareData(10);
}
Thanks in advance for sharing the knowledge.
When you are using forward declarations, you need to make sure that any usage of the forward-declared type which needs full type happens after the type becomes fully defined.
In your case, it means that your code should like following:
class B;
class A
{
public:
B* cObj;
std::vector<B*> cList;
A();
};
class B {
...
};
inline A::A()
{
cObj = new B(*this);
}
Also, while doing so, you certainly would want to get rid of owning B*, and instead use std::unique_ptr there.
The line
cObj = new B(*this);
does not work in A's constructor since the definition of B is not visible at that line. Move the implementation of A's constructor after B has been defined.
class A { ... };
class B { ... };
inline A::A()
{
cObj = new B(*this);
}
cObj = new B(*this);
You cann use B here since it's not yet defined.
Put this under the definition of B:
A::A()
{
cObj = new B(*this);
}
and remove the inline definition.
I have a parent class A and 2 derived class A1 and A2:
class A {
}
class A1 : public class A {}
class A2 : public class A {}
And in another class B I want to keep a collection, which is composed of objects A1 or A2.
class B {
vector<A1> _A1s;
vector<A2> _A2s;
}
Rather than keep 2 separate vectors A1s and A2s, is there a way to combine these 2 vectors? I thought about vector or vector, but either way may lost objects when A1s or A2s resize (I assume).
Any idea?
You can use a vector of smart pointers to base type
std::vector<std::shared_ptr<A>> a_ptr;
Note:
You need to add virtual destructor to A
class A {
public:
virtual ~A() {}
};
usage:
struct B {
public:
B() {
a_ptr.push_back(std::shared_ptr<A>(new A1));
a_ptr.push_back(std::shared_ptr<A>(new A2));
}
private:
std::vector<std::shared_ptr<A>> a_ptr;
};
int main(int argc, char* argv[])
{
B b;
return 0;
}
Also you miss ; after class definition and you have extra keyword class in front of A in below statement:
class A1 : public class A {};
should be:
class A1 : public A {};
You can use a vector of pointer
class B {
public:
std::vector<A*> _AXs;
};
It will accept both A1 and A2 pointer types.
Note that in this case, you should set the destructor of the A class virtual.
If you don't, when you try to delete a A* objet, the program can't guess what is the real type.
class A {
public:
virtual ~A() {}
};
You can use what the others say, plus a design pattern called visitor if you want to still be able to use the underlying A pointer as a A1 or A2. The visitor pattern is not really designed for that but it’s nice to use it that way.
In C++, whose responsibility is it to delete members of a class: the class, or the creator of an instance of that class?
For example, in the following code:
class B {
public:
B(int x) { num = x; }
int num;
};
class A {
public:
A(B* o) { obj = o; }
B* obj;
};
int main(void) {
A myA(new B(3));
return 0;
}
Should main delete the instance of B, or should A's destructor delete its local variable obj? Is this true in most cases, and in which cases if any is it not?
This is a basic question of ownership. If every A should own a B (as in, there should be a new B created when the A is created, that should also be destroyed be the A is destroyed, then you'd normally make A responsible for creating and destroying the instance of B:
class B {
int num;
public:
B(int x) : num(x) {}
};
class A {
B *obj;
public:
A(int value) : obj(new B(value)) {}
~A() { delete B; }
};
In such a case, however, chances are pretty good that A should just be written like:
class A {
B obj;
public:
A(int v) : obj(v) {}
};
int main() {
A a(3);
return 0;
}
This way, the instance of B will be created and destroyed automatically, without any intervention on your part at all.
Almost always A should manage it's members as this is what RAII is based off of. Use unique_ptr when you can.
If it doesn't manage it's data then it should use a different smart pointer, specifically shared_ptr. This shifts the responsibility to the shared_ptr, which is much less error prone than a vanilla pointer.
And of course, the preferred way is to use no pointers at all. Why are you calling new in the first place?
I am trying to use a smart pointer class in the following way
class A
{
friend class B;
virtual methods ();
protected:
virtual ~classA();
}
class B:public QSharedPointer<class A>
{
class B();
~ class B();
}
I plan to replace occurrences of Class A* with class B. Is this approach correct?
No this is not really the way to do this. It looks like your design goal here is to make it impossible for someone to allocate an object of type A without putting it in a smart pointer. The normal way to do this is not to inherit from the smart pointer, but to make your type have
A private constructor
A private destructor
A public static factory method returning in this case QSharedPointer
A private deleter class that is a friend of class A
Here is an example using boost::shared_ptr (I do not have a QT installation right now, but you should be able to just replace all instances of boost::shared_ptr with QSharedPointer)
#include <boost/shared_ptr.hpp>
class A {
private:
A() {}
~A() {}
struct deleter {
void operator()(A* val) {delete val;}
};
friend class deleter;
public:
static boost::shared_ptr<A> create() {
return boost::shared_ptr<A>(new A(), A::deleter());
}
};
int main()
{
//A a1; //compile error
//A *a2 = new A(); //compile error
boost::shared_ptr<A> a3 = A::create();
return 0;
}