【问题标题】:Assign class constructor to a new constructor with parameter in C++在 C++ 中将类构造函数分配给带有参数的新构造函数
【发布时间】:2013-11-05 09:26:44
【问题描述】:

我创建了一个类类型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;   
}

【问题讨论】:

    标签: c++ function class constructor dynamic-arrays


    【解决方案1】:

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

    作为最佳做法,我建议添加您自己的:
    - 复制构造函数
    - 复制作业
    (参见rule of three)

    关于变量成员a设计:
    - 如果你想让t1和t2指向同一个数组,那么你可以使用shared_ptr
    - 如果您希望t1 和t2 拥有自己的数组,那么将vector<int> 用于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;   
    }
    

    【讨论】:

    • 可以,但是你需要在你的拷贝构造函数和拷贝赋值中管理指针。恕我直言,我上面提到的设计(第二个)比操作原始指针更容易实现。
    • (如下),例如,这里是一个简单的复制构造函数操作原始指针的例子:Test(const Test& that) { int size = sizeof(that.a); this->a = new int[size]; memcpy (this->a, that.a, sizeof (size)) ; }
    • 你能告诉我完整的代码来实现我的目的吗?我是新来的班级,拜托。谢谢:)
    • @user2879534 我更新了我的答案。稍后,您可能想要使用 vector 并比较实现。
    • 哈哈你的权利!所以向量没有这个问题吗?原因,没有向量的指针?
    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2022-01-18
      • 2015-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-25
      • 2011-09-05
      • 2015-06-30
      • 2018-06-03
      相关资源
      最近更新 更多