在 return 之后重写的数组内容

Content of array being rewritten after return

首先,我有下面的 class A,同时有一个嵌套的 class B:

// A.h
class A {
public:
    class B;

    A();
    A(const A& a); // Copy constructor

    B& operator[](const unsigned int& a) const;
    A operator+(const A& a) const;

    /*...*/

    ~A();
private:
    /*...*/
    unsigned int size;
    B* b;
};

我正在尝试通过添加所述对象的两个 b 成员的内容,将重载的 + 运算符用于 "add" 两个 A 对象,并且将结果分配给第三个 A 对象。

这是主要功能:

// main.cpp
int main(int argc, char** argv) {
    A a1, a2, result;

    a1.read(argv[1]); // Initialize b member with content read from a file
    a2.read(argv[2]); // Initialize b member with content read from a file

    result = a1 + a2; // Error [3]

    getchar();

    return 0;
}

问题是,在尝试求和时,我得到了我认为是内存错误的内容,例如:HEAP[main.exe]: Invalid address specified to RtlValidateHeap( 00A50000, 00A59938 )

这里是 class A 的实现:

// A.cpp
A::A() : /*...*/, size(0), b(nullptr) {}

// Copy constructor
A::A(const A& a) : /*...*/, size(a.size), b(nullptr) {
    b = new B[size]; // [1]

    for (unsigned int i = 0; i < size; i++) {
        (*this)[i] = a[i];
    }
}

A::B& A::operator[](const unsigned int& i) const {
    return b[i];
}

A A::operator+(const A& a) const {
    if (size != a.size) {
        exit(1); // Size must be the same on both operands
    }

    A tmp(*this); // Call to copy constructor

    for (unsigned int i = 0; i < a.size; i++) {
        tmp[i] += a[i];
    }

    return tmp; // Call to copy constructor [2]
}

A::~A() {
    if (b != nullptr) {
        delete[] b;
    }
}

和 class B:

// B.h
class A::B {
public:
    B();
    B(unsigned char, unsigned char, unsigned char);

    B& operator+=(const B& b);
private:
    unsigned int a, b, c, d;
};

// B.cpp
A::B::B() : a(0), b(0), c(0), d(0) {}
A::B::B(unsigned char _a, unsigned char _b, unsigned char _c) {
    /*...*/
}

A::B& A::B::operator+=(const B& b) {
    /*...*/

    return *this;
}

顺便说一句,我正在使用 Visual Studio,在调试时我观察到:

  1. b 成员 result 指向与 b[1] 中相同的地址时[2] 中的 return 语句调用了复制构造函数,目前一切顺利

  2. 直到[2]中的returnb的内容就可以了,比如:0x00669968 00 00 ff 00 00 ff 00 00 ..ÿ..ÿ..

  3. [3]之后b的内容在[1]中因此内容result 对象的 b 成员变成类似:0x00669968 dd dd dd dd dd dd dd dd ÝÝÝÝÝÝÝÝ,我猜是垃圾

注意:所有 include 指令和不相关的代码部分已被省略

两天来我一直在摇头试图找出问题所在,但运气不好,所以非常感谢您的帮助,在此先感谢。

我检查了您的代码,问题是您需要 class A 的自定义复制分配。在您的 main 中,您有 A a1, a2, result;,为 3 个对象调用了默认构造函数。然后,在result = a1 + a2;行中调用了默认的复制赋值。

When you have pointers in your class and allocate the memory using new then you have to worry about copy constructor and copy assignment. Check this post and the rule of three.


我建议你下一个代码:

class A {
    class B {
        unsigned a, b, c, d;

    public:
        B() : a(0), b(0), c(0), d(0) { }

        B(unsigned char a_, unsigned char b_, unsigned char c_) : a(a_), b(b_), c(c_), d(0) { }

        // Copy constructor.
        B& operator=(const B& b_) {
            a = b_.a;
            b = b_.b;
            c = b_.c;
            d = b_.d;
            return *this;
        }

        B& operator+=(const B& b_) {
            a += b_.a;
            b += b_.b;
            c += b_.c;
            d += b_.d;
            return *this;
        }
    };

    unsigned size;
    B* b;

public:
    A() : size(0) { }

    // Copy constructor.
    A(const A& a) : size(a.size) {
        b = new B[size];
        for (unsigned i = 0; i < size; ++i) {
            b[i] = a[i];
        }
    }

    // Copy assigment
    A& operator=(const A& a) {
        clear();
        b = new B[size];
        for (unsigned i = 0; i < size; ++i) {
            b[i] = a[i];
        }
        return *this;
    }

    B& operator[](unsigned pos) const {
        if (pos > size) {
            throw std::out_of_range("Out of range");
        }
        return b[pos];
    }

    A operator+(const A& a) const {
        A tmp = *this;
        if (size != a.size) {
            throw std::out_of_range("Diferent sizes");
        }
        for (unsigned i = 0; i < a.size; ++i) {
            tmp[i] += a[i];
        }
        return tmp;
    }

    void read(const char* file) {
        clear();
        size = size_;
        b = new B[size];
        /*
         * Read your file and update b.
         */
    }

    void clear() {
        if (size) {
            delete[] b;
            size = 0;
        }
    }

    ~A() {
        clear();
    }
};