2012-02-17 43 views
1

我有以下示例代码。类bar源自基类foo并为ptr_x分配内存,同时通过基类授予读取/写入访问权限。这是一个大型代码的玩具模型,其中读/写函数对于对象的所有不同变体都是相同的,但是在不同的变体中内存分配略有不同。在基类中的运算符定义

#include <iostream> 

class foo{ 
protected: 
    int *ptr_x; 

public: 
    foo(){ 
     std::cout << " 1) Inside foo constructor: " << ptr_x << std::endl; 
    } 

    void read() 
    { 
     std::cout << " 2) Inside read function: " << ptr_x << std::endl;  
     std::cout << " 3) Inside read function: " << *ptr_x << std::endl; 
    } 
    void operator=(const int rhs) 
    { 
     std::cout << " 4) Inside operator= : " << ptr_x << std::endl; 
     *ptr_x = rhs; 
    }   
}; 
class bar: public foo{ 

public: 
    bar(int a) 
    : foo() 
    { 
     std::cout << " 5) Inside bar constructor: " << ptr_x << std::endl; 
     ptr_x = new int; 
     std::cout << " 6) Inside bar constructor: " << ptr_x << std::endl; 
     *ptr_x = a; 
    } 
    ~bar() 
    { 
     std::cout << " 7) Inside bar destructor: " << ptr_x << std::endl; 
     if (ptr_x != NULL) {delete ptr_x; ptr_x = NULL;} 
    } 
}; 
int main(){ 
    bar a(20); 
    a.read(); 
    a = 40; 
    a.read(); 
    return 0; 
} 

当我运行代码,我得到:

1) Inside foo constructor: 0 
5) Inside bar constructor: 0 
6) Inside bar constructor: 0x1d8f010 
2) Inside read function: 0x1d8f010 
3) Inside read function: 20 
1) Inside foo constructor: 0x7f40c11e3b68 
5) Inside bar constructor: 0x7f40c11e3b68 
6) Inside bar constructor: 0x1d8f030 
7) Inside bar destructor: 0x1d8f030 
2) Inside read function: 0x1d8f030 
3) Inside read function: 0 
7) Inside bar destructor: 0x1d8f030 
*** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0000000001d8f030 *** 

我有以下几个问题:1)为什么不代码输入的基类operator=? 2)为什么第二次调用构造函数/析构函数? 3)为什么会出现double free问题?

我究竟做错了什么?

编辑:好的double free问题是显而易见的,但为什么会出现相同的内存位置的两个实例?这不知何故与operator=有关,因为当我评论它一切都很好。

由于

回答

2

推理所观察到的行为:

编译器使用在派生类的转换构造,

bar(int a) 

评价:

a = 40; 

这需要在整合er 40,并使用转换构造函数创建bar对象,然后使用编译器为类bar生成的隐式复制赋值运算符(=)将创建的bar对象指定给a

这就是您看到对bar构造函数的额外调用以及从未调用基类重载=的原因。另外,对于双自由就在于这里的原因,你有多个bar对象,其保持指向分配给ptr_x和动态内存当对象的一个​​超出范围的析构函数被调用这将释放内存,但离开其他对象中的成员指针处于悬挂状态。

如何解决这些问题:
你应该标记转换构造explicit,如果你不想让编译器使用它这样的隐式转换。

您应该遵循Rule of Threebar类。

警告:
。注意,在基类的操作者=总是由隐式生成=操作者派生类隐藏。

+0

谢谢。这是否意味着我总是必须为派生类定义'='运算符?什么是运营商是这样的? – GradGuy 2012-02-17 06:44:39

+0

@GradGuy:如果你不为你的派生类重新定义'='运算符,编译器会隐式生成它,从而隐藏基类'='。阅读更多关于[功能隐藏](http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9)的信息,这应该能让你很好地了解相同情况的适用情况。 – 2012-02-17 07:04:53

1

对于你刚才应该申报 bar (int a)的第一个问题是

explicit bar(int a). 

这给出了一个合适的编译错误类酒吧应该有=运营商定义的。