班级成员突然变得无法访问/不存在

时间:2014-12-12 17:13:52

标签: c++ class memory destructor

在我的主要内容中,我在循环中调用函数(func1)。此函数是Class1的成员。我将另一个类object2的对象(Class2)传递给此函数。在循环的第一次迭代中,变量var2Class2的成员)可以从main访问,但在第二次迭代中,它不是。我得到了一个"访问违规读取位置"错误。这是我的代码:

main.cpp中:

#include "Class1.h"
int main(){

    Class2 object2;
    object2.assign_var2();
    Class1 object1;


    for (int i = 0; i < 2; ++i){
        std::cout << object2.var[0][0][0] << std::endl; // Works ONLY on first iteration
        object1.func1(object2)
    }
}

Class2.h:

class Class2{
    ... other variables and functions declared
    public:
    Class2::Class2();
    Class2::~Class2();
    double *** var2;
    void assign_var2();
}

Class2.cpp:

Class2::Class2(){

var2 = new double**[200];
for (int i = 0; i < 200; ++i) {
    var2[i] = new double*[200];

    for (int j = 0; j < 200; ++j){
    var2[i][j] = new double[2];
    }
}

Class2::~Class2(){
for (int i = 0; i < 200; ++i){
    for (int j = 0; j < 200; ++j){
        delete [] var2[i][j];
    }
    delete [] var2[i];
}
delete [] var2;
}

void assign_var2(){
for (int i = 0; i<200; ++i){
    for (int j = 0; j<200; ++j){

        var2[i][j][0] = some_number1;
        var2[i][j][1] = some_number2;
    }
}
}
}

Class1.h:

#include "Class2.h"
class Class1{
    ... other variables, functions declared
    public:
    void func1(Class2)

}

Class1.cpp:

Class1::func1(Class2 object2){
    int u = object2.var2[1][2][0];
    int v = object2.var2[1][2][1];
}

旁注:如果我尝试打印另一个变量而不是var2,它似乎在第二次迭代时工作,所以我不认为这是对象本身的问题。

提前致谢!!

1 个答案:

答案 0 :(得分:3)

问题是Class1::func1(Class2 object2)按值接受参数。这意味着正在制作Class2对象的副本,然后在func1()返回时被销毁。

Class2类中,您没有定义复制构造函数,因此编译器正在为您创建一个只按副本复制成员的程序。然后当副本的析构函数运行时,它delete的所有分配,使原始对象留下指向无效对象的指针。这就是它在第二次迭代中失败的原因。

始终遵循rule of three:如果您需要自定义析构函数,复制构造函数或复制赋值运算符,您需要所有这三个。正确的复制构造函数将为所有阵列创建新的分配并将数据复制到它们。 (如果您使用的是C ++ 11,那么它实际上是五个的规则:您可能还想实现一个移动构造函数并移动赋值运算符,以便您可以“窃取”var2指针,如果你知道被分配的对象是一个右值,因此无论如何都会很快消失。)

在您的情况下,修复很简单:按值接受参数:

Class1::func1(Class2 const & object2)

我强烈建议您使用std::vector<std::vector<std::vector<double>>>作为var2成员,因为编译器生成的析构函数,复制构造函数和复制赋值运算符都会做正确的事情,并且您赢了不需要实施任何一个。

这与使func1()接受引用一起工作:当错误发生时因为没有自定义复制构造函数,我们甚至不想在这里复制,因为我们'不修改数据。仅复制数据以销毁副本是愚蠢的;让我们接受对现有对象的引用,而不是需要多余的副本。

或者,您可以完全禁用复制:

class Class2 {
    // ...

    // For C++11: explicitly delete the copy-ctor and copy-assignment operator.
public:
    Class2(Class2 const &) = delete;
    Class2 & operator=(Class2 const &) = delete;

    // For C++03: declare the copy-ctor and copy-assignment operator private and
    // then do not implement them. (C++03 doesn't have the "= delete" syntax.)
private:
    Class2(Class2 const &);
    Class2 & operator=(Class2 const &);

如果禁用复制,则会在调用object1.func1(object2)上收到编译时错误,因为它取决于object2的复制构造函数是否存在。