类成员突然变得不可访问/不存在

Class member suddenly becomes inaccessible/non-existent

本文关键字:访问 不存在 成员 突然      更新时间:2023-10-16

在我的main中,我在循环中调用一个函数(func1(。此函数是 Class1 的成员。我正在传递一个不同类的对象(object2(,Class2到这个函数。在循环的第一次迭代中,变量 var2(Class2 的成员(可以从 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)
    }
}

类2.h:

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

2类.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;
    }
}
}
}

1.h类:

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

}

类1.cpp:

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

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

提前感谢!!

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

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

始终遵循三个规则:如果需要自定义析构函数、复制构造函数或复制赋值运算符,则需要所有三个。正确的复制构造函数将为所有数组创建新的分配并将数据复制到其中。(如果您使用的是 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 的复制构造函数。