【问题标题】:Memory Allocation in C++ (Exception thrown: read access violation.)C++ 中的内存分配(抛出异常:读取访问冲突。)
【发布时间】:2019-10-29 23:07:08
【问题描述】:

我正在努力学习更多 C++ 知识! 在处理了一段时间的内存分配之后,我到了一个我很难理解它的地方。

我编写了一个代码,对于一种初始化类型(某个类的对象)运行良好(不太确定,但至少没有显示任何内存违规),但它在进行类似的初始化时会崩溃。

如果有人能解释发生了什么以及如何解决这个问题,我将不胜感激。

我的想法:问题出在下面一行,因为我试图删除一组分配的对象,而在有问题的初始化中我只分配了一个对象而不是数组。

delete[] pointer; //PROBLEMATIC LINE

PS.:我不是在寻找替代解决方案(例如使用智能指针或其他)。对不起我的英语!

代码:

class class1
{
private:
    unsigned int    s;
    double* pointer;
public:
/* Constructors */
    class1() { s = 0; pointer = nullptr; }
    class1(unsigned int us, double* uarray)
    {
        pointer = new double[us];
        for (unsigned int i = 0; i < us; i++)
            pointer[i] = uarray[i];
    }
    class1(const class1& other)
    {
        pointer = new double[s];
        for (unsigned int i = 0; i < s; i++)
            pointer[i] = other.pointer[i];
    }
    ~class1() { if (!s && pointer != nullptr) delete[] pointer; }

public:
/* Operators Overloading */
    class1& operator=(const class1& other)
    {
        s = other.s;
        pointer = new double[s];
        for (unsigned int i = 0; i < s; i++)
            pointer[i] = other.pointer[i];
        return *this;
    }
};

class class2
{
private:
    unsigned int    m;
    unsigned int    n;
    class1* pointer;

public:
/* Constructors */
    class2(unsigned int un, double* uarray, bool flag = false) : n(un)
    {
        m = 1;
        pointer = new class1(un, uarray);
        if (flag) { this->function(); }
    }
    ~class2() { if (!m && !n) delete[] pointer; }

public:
/* Public Methods */
    void function()
    {
        class1* newpointer = new class1[n];
        //**... some code (when commented show the same error)**
        delete[] pointer; //**PROBLEMATIC LINE**
        pointer = newpointer;
    }

public:
/*Template Constructor*/
    template<unsigned int m, unsigned int n>
    class2(unsigned int um, unsigned int un, double(&uarray)[m][n], bool flag = false) : m(um), n(un)
    {
        pointer = new class1[um];
        for (unsigned int i = 0; i < um; i++)
        {
            class1 object1(un, uarray[i]);
            pointer[i] = object1;
        }
        if (flag) { this->function(); }
    }
};

int main()
{
    double test3[] = { 1, 2, 3 };
    double test4[][3] = { {3, 2, 1}, {6, 5, 4}, {9, 8, 7} };
    double test5[][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };

    class2 m4(3, test3, true);      //**NOT OK - VIOLATION OF MEMORY**
    class2 m5(3, 3, test4, true);   //**OK**
}

【问题讨论】:

  • 我看到至少三个未定义行为的实例,即未初始化的变量使用(在function(),在特定代码路径之后的析构函数之一中,以及在复制构造函数中),以及其他类似的错误.显示的代码需要废弃并从头开始重写。
  • 请不要更正代码中与您的问题相关的错误。它使其他人无法遵循问题和答案。我回滚了你的编辑。

标签: c++ memory allocation access-violation


【解决方案1】:

class1 的复制构造函数没有设置 s 成员,而是在此处使用其不确定值:

pointer = new double[s];

导致未定义的行为。在使用之前将s 设置为other.s


你的第二个构造函数也有同样的问题。


class1 的赋值运算符正在泄漏内存,因为它没有 delete[] 前一个数组。


class2 中,您使用非数组形式的new,例如这里:

pointer = new class1(un, uarray);

但是在析构函数中调用delete[] 来删除pointer。这也会导致未定义的行为。从new 的非数组版本返回的指针需要被delete 删除,例如delete pointer.

但是由于您还使用new 的数组版本来表示pointer,因此您也不能使用delete pointer。因为在从新数组返回的指针上使用 delete 而不是 delete[] 也具有未定义的行为。

保持一致并始终使用新数组,例如:

pointer = new class1[1]{{un, uarray}};

class2 在复制或移动其类型的对象时会导致未定义的行为,因为尽管定义了析构函数,但您没有实现复制构造函数和赋值运算符。这违反了rule-of-three


我可能错过了更多。代码根本不可读。下次请使用正确的变量名。 (希望真正的代码不要使用这种命名方案……)有一个非类型模板参数m 与该类的成员同名,然后在该上下文的多个位置使用m 是不行的。我必须检查查找规则以确保它确实可以编译并执行一些合理的操作。

【讨论】:

  • s 也没有在两个参数构造函数中设置。
  • 是的,这是一个问题,但不是唯一的问题。例如,提问者指出delete[] pointer; 导致了问题,而pointer 在一种情况下可能已分配有pointer = new class1(un, uarray);。这是 UB,因为 newdelete[] 混合在一起。
  • 另见这篇文章,了解 delete[] 和 delete 之间的区别。 stackoverflow.com/questions/4255598/delete-vs-delete
  • function() 中还有未初始化的变量用法,它直接从显示的代码中调用。基本上,显示的代码是一团糟。此外,还有一些有用的 cmets 指示已删除的代码,这可能隐藏了许多其他惊喜。
  • @SamVarshavchik 最初我认为我可以通过代码并将错误一一添加到我的答案中。也许那是个错误。
猜你喜欢
  • 2018-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-01
  • 2016-08-25
  • 1970-01-01
  • 2022-01-08
  • 2021-05-01
相关资源
最近更新 更多