2012-08-02 66 views
1

我正在尝试执行类B的深层复制,但A没有设置。如何在C++中执行深层复制

为什么b3->print返回一个垃圾数字而不是1

据我所知,b2和b3都指向同一个A对象。但我用B的拷贝构造函数在堆上创建了一个新对象。那么他们为什么仍然在向同一个对象倾诉呢?

我希望这是有道理的。

#include <cstdlib> 
#include <iostream> 

using namespace std; 

class A{ 
     int num; 
public: 
     A(int n):num(n){ cout<< "A "<< num << " constructor" <<endl;} 
     ~A(){ cout<< "A "<< num <<" destructor. " <<endl; } 

     int print(){ 
     cout<< num<< endl; 
     } 
}; 

class B{ 
     A *a; 
     int num; 
public: 
     B(int n):num(n){ 
      a = new A(n); 
      cout<< "B "<< num <<" constructor" <<endl;  
     } 
     ~B(){ 
      delete a; 
      cout<< "B "<< num <<" destructor"<<endl; 
     }  
     // Copy contructor 
     B(const B & b): a(new A(b.num)){ 
     } 

     <strike>int<\strike> void print(){ 
     cout<< num << endl; 
     } 

     int get_num(){ 
      return num; 
     } 
}; 

int main(int argc, char *argv[]) 
{ 
    B *b2 = new B(1); 
    B *b3(b2); 
    b2->print(); 
    delete b2; 
    b3->print(); 
    system("PAUSE"); 
    return EXIT_SUCCESS; 
} 
+2

由于没有任何析构函数是虚拟的,最简单的答案是摆脱指针和'new'并简单地使用值。 – 2012-08-02 17:28:34

+1

(http://stackoverflow.com/questions/4172722/) – fredoverflow 2012-08-02 17:35:23

回答

10

B *b3(b2);不会做你的想法。

这相当于B* b3 = b2。指针将指向相同的位置。当您执行delete b2;时,您还可以释放由b3指向的内存。

做一次深层副本,这样做:

B* b3 = new B(*b2); 

还有这里的未定义行为:

int print(){ 
    cout<< num << endl; 
} 

因为你永远不回来。将退货类型更改为void

获得的价值预计:

B(const B & b): a(new A(b.num)), num(b.num){ 
} 
+1

为了让OP更清楚,你没有在B的拷贝构造函数中复制'num',你所做的就是将'num'拷贝到' a.num' – Haozhun 2012-08-02 17:29:02

0

我想你可能打算写这样的事:

#include <iostream> 

class A 
{ 
public: 
    A(int n) : num_(n) {} 

    void print() { std::cout << num() << std::endl; } 

    int num() const { return num_; } 

private: 
    int num_; 
}; 

class B 
{ 
public: 
    B(int n) : a(n) {} 

    int num() const { return a.num(); } 

private: 
    A a; 
}; 

int main() 
{ 
    B b(1); 
    B b2 = b; // deep copy 
} 

正如你可以看到:

  1. B不有自己的num_成员。应避免重复。
  2. 没有必要实现复制构造函数或赋值运算符(三规则)。
  3. 这里不需要使用new
-6

在C++中没有浅/深的拷贝。您可以获取复制的值或指针/引用,并完全定义复制操作的语义。

+2

错!深/浅拷贝确实存在。您可以复制指针,并且可以深度复制指针。 – 2012-08-02 17:32:49

+0

@LuchianGrigore'T * p2 = new T(* p1);'不复制一个指针,它通过一个指针复制一个对象,并得到一个指向副本的指针。 – 2012-08-02 17:34:32

+0

这不是我所争论的。我在争论你的第一个陈述 - “在C++中没有浅层/深层拷贝”,这是完全错误的和误导的。 – 2012-08-02 17:35:38

0

这里你是不是抄袭B2

B *b3(b2); 

,而不是你正在B3点B2

你应该有

B *b3 = new B(*b2); 
1

其他这个问题的答案会指点一下如何工作的解释,但你也应该明白,不使用指针是一个更好的解决方案。 C++的默认行为可以很好地处理值语义。如果您按值保存对象,则缺省副本ctor和赋值运算符将执行“深度复制”。

class B{ 
    A a; 
    int num; 
public: 
    B(int n): a(n), num(n){ 
     cout<< "B "<< num <<" constructor" <<endl;  
    }  

    void print(){ 
     cout<< num << endl; 
    } 

    int get_num(){ 
     return num; 
    } 
}; 

另外,如果你确实使用拥有指针,你通常应该使用智能指针。