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

时间:2016-12-08 03:03:02

标签: c++ constructor arguments pass-by-reference lvalue

我正在尝试编写两个类AB,其中B包含类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::B(A& a)时,参数将被复制到ba中的实例B中。如果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分配的内存。

如果我们使用A,是否有方便的方法将对象B(在B之外创建)的“引用”传递给构造函数中的B::B(A& a)如果我们使用B :: B(),创建一个空的,默认的A对象?我试过了

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

但它给出“左值必须在赋值左侧”错误。

任何建议表示赞赏。对不起这篇文章太长了。

3 个答案:

答案 0 :(得分:2)

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

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.

答案 1 :(得分:1)

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

class B{
private:
    A* ba;

答案 2 :(得分:1)

这取决于您的设计。如果您希望B拥有A std::move,请A获取B

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

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