1

我创建了一个类类型Test和带参数的构造函数,但是,当我想通过函数f将我创建的构造函数分配给新的构造函数时,程序崩溃了!有人知道为什么吗!?

编码:

class Test
{
  public:
    int number;
    int *a;
    Test(int n){
        a = new int[n];
    }
    ~Test(){
        delete []a;
    }
};

Test f(Test Ft1)
{   
     // Do something.
     return Ft1;
}

int main()
{   
    Test t1(3);
    t1.number = 5;
    Test t2 = f(t1);    
    return 0;   
}
4

2 回答 2

2

a问题是当t1t2析构函数被调用 时你删除了两次相同的数组:t1并且t2它们的成员变量a指向相同的内存位置。当您这样做时Test t2 = f(t1),会创建一个副本t1并将其分配给t2. 您没有定义特定的复制构造函数,因此编译器为您隐式定义了它。然而,它只是简单地复制了 的值a(并且不会new像您期望的那样进行分配)。

作为最佳实践,我建议添加您自己的:
- 复制构造函数
- 复制赋值
(cf rule of three

关于变量成员a设计:
- 如果你想t1t2指向同一个数组,那么你可以使用shared_ptr
- 如果你想t1t2有自己的数组,那么使用vector<int>for会更简单a

编辑:如果您需要使用原始指针,这里有一个快速示例,说明如何在复制构造函数和运算符分配中管理内存。我可以建议您阅读有关它的参考书(例如Effective C++ , chapter 11)吗?它将向您解释关键概念和陷阱。

class Test{
public:
    int number;
    int *a;
    Test(int n){
        a = new int[n];
    }
    ~Test(){
        delete [] a;
    }
    Test(const Test& that)
    {
        int size = sizeof(that.a);
        a = new int[size];
        memcpy (a, that.a, sizeof(size));
    }
    Test& operator=(const Test& that)
    {
        if (this != &that)
        {
            delete [] a;
            int size = sizeof(that.a);
            a = new int[size];
            memcpy (a, that.a, sizeof(size));
        }
        return *this;
    }
};

Test f(Test Ft1){   
    //do something
    return Ft1;
}

int main(){ 
    Test t1(3);
    t1.number = 5;
    Test t2 = f(t1);
    // Test t3(t1);  // calls copy constructor
    // t3 = t1; // calls assignment operator
    return 0;   
}
于 2013-10-26T06:44:52.227 回答
2

您的问题的原因是有一种叫做“二进制副本”的东西。当没有定义特殊的赋值/复制构造函数时,这个二进制副本就会启动。当你的一个对象被复制到另一个对象上时,2个不同的实例开始拥有同一个数组,因为指针被覆盖并且目标对象的原始数组被泄露。

编译器认为可以通过简单的方式将一个对象的内容复制到另一个对象中memcpy()(图片稍微简化了一些,但本质上我写的是正确的)。这是问题的源头,但这就是语言的定义方式。今天没有其他方法可以做到这一点。编写了大量代码,而这些代码正是如此。

首先,您需要决定在复制后该数组会发生什么。如果这两个对象都是co-own源对象的数组,这个数组是否应该在此时复制或其他任何东西。一旦你决定了这一点,你需要在赋值/复制构造函数中实现这个策略。

于 2013-10-26T07:02:28.870 回答