了解复制构造函数

时间:2013-08-06 18:43:17

标签: c++ copy-constructor

我已经读过,如果我们在类中有指针,那么我们需要实现自己的复制构造函数;否则,两个类将指向同一个内存位置的指针,并且在其中一个类上调用delete会使另一个类也为空。 我试图通过编写如下代码来模拟上述条件:

class A
{
    private:
        int *p;
    public:
        A()
        {
            p = new int(10);
        }

        ~A()
        {
            delete p;
            cout << "Calling destructor" << endl;
        }
};

int main(int argc, char **argv)
{
    A a;
    A aa = a;
}

我期待抛出一些异常,因为我没有显式声明我的拷贝构造函数,我也在使用指针。但程序运行完美。任何人都可以建议修改,以便我能够理解在什么条件下会发生异常?

4 个答案:

答案 0 :(得分:5)

您的代码执行delete两次相同的指针。这是 未定义的行为,以及可能的症状之一 未定义的行为是它似乎可以工作。 (在我的 经验,最常见的症状是一切正常 完美,直到你把它呈现给公众,在那个时候,它 开始左右崩溃。)

答案 1 :(得分:1)

您的问题与指向一个实例的两个指针并删除实例的问题相同。

给出以下代码:

int main(void)
{
    int * pointer_1 = NULL;
    int * pointer_2 = NULL;

    pointer_1 = new int;
    *pointer_1 = 42;

    // Make both pointers point to the same dynamically allocated object.
    pointer_2 = pointer_1;

    // Let's delete the instance
    delete pointer_1;

    // The delete operator does not change the value of pointer_1.
    // Pointer_1 still points to *something*, but that *something* has been deleted.

    return 0;
}

在上面的示例中,delete不会影响pointer_1pointer_2的值。只有对象不再存在。 C或C ++标准中没有任何内容表明在删除内存或更改指针时必须通知程序。

没有任何说明当删除内存时,实现必须更改指向已删除内存的每个指针。

因为对象不再存在,所以引用指针将生成未定义的行为。内容可能在内存中有阴影,或者操作系统可能已从内存中完全删除了页面(例如,内存分页)。

操作系统可能会抛出异常,但C和C ++语言不会强制编译器库生成异常。毕竟,在某些嵌入式系统中,地址0是有效的内存位置。

尝试在每一步打印指针的值以进行验证。

我告诉你和你的朋友指着地板上的地毯。我删除了地毯。你和你的朋友指的是什么?

答案 2 :(得分:0)

像这样的东西

A * a = new A();
A * b = a;
delete a;
stdout << (*(b->p));

但是delete应该只为程序的其他部分使用内存,而不一定是null

答案 3 :(得分:0)

我不认为每次发言都会引发“例外”。您可能会遇到像SEGV或更糟的内存损坏等不良副作用。要理解为什么需要复制构造函数,您可以考虑对象'a'和'aa'的外观。

假设,new int(10)返回一个指针值0xfeedface,其中*(int *)(0xfeedface)== 10.你的对象看起来像,

a - &gt; {p = 0xfeedface} aa - &gt; {p = 0xfeedface}

现在,如果你破坏对象 - 一个内存'0xfeedfac'e将得到未分配的&amp;回到你的分配器freelist。考虑对象aa会发生什么。它仍然保持对0xfeedface的引用,但是已经释放的内存!现在,如果object-aa尝试取消引用* p,它可以获得潜在的随机值(取决于分配器的作用或者对象是否已分配给其他对象)。此外,如果object-aa试图写入p = 0xfeedface,可能会发生可怕的事情。

如果你想要写一个拷贝构造函数,我能想到的一种方法是创建一个基类&amp;如果它被调用则断言。

#include <iostream>
#include <cassert>

class base
{
    public:
        virtual void operator=(const base& )
        {   
            assert(! "No copy constructor for class derived from base");
        }   
};

class derived : public base
{};

int
main()
{
   derived d, d1; 
   d1 = d;
}

上面的代码将断言,因为派生类没有提供复制构造函数。在编译时将其捕获是理想的。但我现在想不出一种方法。

[警告:上述解决方案不适用于多级继承]