C++ 初始化包含另一个对象设计问题的对象

C++ initializing an object that contains another object design issue

我正在尝试编写两个 classes AB,其中 B 包含 class A 的实例。实际上,A 包含一些大数据。在这个玩具示例中,我们假设它们如下:

class A{
public:
    int a;
    A(){}
    A(const A& ac){
       cout <<"copy constructor for A" << endl;
       a = ac.a;
    }
    virtual ~A(){}
    A& operator=(const A& that){
      cout <<"operator = for A" << endl;
      a = that.a;
      return *this;
   }
};
class B{
private:
    A ba;
public:
    B(){  a = A();  }
    B(A& a){
        cout << "Using default constructor" << endl;
        ba = a;
    }
    B(const B& copy){
        cout<<"copy"<< endl; ba = copy.ba;
    }
    B& operator=( const B& that){
       cout<<"invoking operator = "<< k<< endl;
       ba = that.ba;
       return *this;
    }
    virtual ~B(){}
    A& getA(){ return ba; }
    void printAadrr(){
        cout << &ba <<" "<< ba.a<< endl;
    }
};

问题在于,当使用 B::B(A& a) 初始化 B 时,参数被复制到 B 中的实例 ba 中。如果 a 很大,它可能效率低下。

我想到了另一种方法,而不是

class B{
private:
    A ba;
    ....

我可以

class B{
    private:
        A* ba;
public:
    B(){  
       ba = new A(); //but we have to free memory in destructor if we call default constructor
    }
    B(A& a){
        cout << "Using default constructor" << endl;
        ba = &a;
    }

但是这种设计选择有其自身的问题,如果我将 B 作为默认构造函数,我需要在稍后的析构函数中释放分配给 ba 的内存。

如果我们使用 B::B(A& a) 并创建一个空的默认 A 对象,如果我们使用 B::B()?我试过了

B::B(A& a){
    &ba = &a;
}

但它给出 "lvalue has to be on the left of assignment" 错误。

如有任何建议,我们将不胜感激。抱歉太长了 post.

不要将 A 作为简​​单的成员 var,而是要有指向 A 的指针。然后在构造 B 时,只需将指针传递给 A 的实例即可。

class B{
private:
    A* ba;

这取决于您的设计。如果你想 B 拥有 A 使用 std::move 通过 B 获得 A

一般情况下使用std::shared_ptr,它将自行管理内存。 std::shared_ptr<A>的所有实例被销毁后,A的数据也将被删除。但在这种情况下 B 个实例可以 共享 相同的 A 数据。

其他解决方案是 std::unique_ptr,但每次复制 B 时都必须移动它,这意味着 A 的所有权将与 std::move 解决方案一样转移。

使用移动语义定义构造函数如下:

B::B( A && a )
: ba( std::move( a ) )
{}

现在您可以将实例传输到对象中。

A a;
B b( std::move( a ) );
// `b` stores content of `a`, and local `a` is no longer valid.

如果您想要,您仍然可以使用复制构造函数构造。

A a;
B b( a );
// `b` stores a copy of `a`, and local `a` is still valid.