虽然它不应该被调用,但为什么要调用d?tor?

时间:2016-09-04 13:30:40

标签: c++ class

我试图初始化我自己的int数组的类,但运算符重载中的某些东西是不起作用的,因为某些原因我的对象的调用是在我想要它之前调用它并且它使我的代码崩溃:

#include "stdafx.h"
#include "Array.h"

int _tmain(int argc, _TCHAR* argv[])
{
    Array arr(6);
    arr[3] = 6; //code crashes here
    printf("%d\n", arr[0]);
    return 0;
}

现在上课: 头文件:

#pragma once
#include <malloc.h>
class Array
{
public:
//ctor dtor and operator overloading
    Array(int);
    Array(int *, int);
    ~Array();
    Array operator[](int i);
//here memebers are defined
    int *arr;
    int size;
};

---- cpp file ---

#include "stdafx.h"
#include "Array.h"

//the function mallocs size for the array.

Array::Array(int g = 1) :size(g) //diplomatic value for size =1
{
    this->arr = (int*)malloc(sizeof(int) * this->size);

}
Array::Array(int *p, int m_size=1) :arr(p), size(m_size)
{} 

Array::~Array()
{
    delete arr;
}

在此功能之后,我的对象被d&#39; tor

删除
Array Array::operator[] (int i){
    for (int j=0; j < i; ++j)
    {
        ++(this->arr);
    }
    return *this;
}

2 个答案:

答案 0 :(得分:2)

因为operator[]函数按值返回Array个对象。这意味着当你执行赋值arr[3] = 6时,运算符返回this的副本,然后编译器从整数6隐式创建一个数组对象(因为它有一个匹配的构造函数)并突然你的作业看起来像是

arr[3] = Array(6);

某处临时数组对象(由operator[]函数返回的对象,以及编译器在赋值右侧创建的对象)必须被破坏,但到那时你有多个对象全部在自己内部使用相同的指针arr。第一个临时对象被破坏,它删除指针,使所有其他对象留下无效指针。然后破坏下一个临时对象并尝试删除现在无效的指针。砰的一声,你有一个崩溃。

要解决问题,您需要做两件事。第一个是认识到operator[]函数返回错误的类型,它应该返回对包含数组的元素的引用:

int& Array::operator[](size_t const i)
{
    return arr[i];
}

您需要做的第二件事是阅读the rules of three, five and zero

另外,为了防止编译器错误地从int值构造对象,您应该将构造函数标记为explicit

explicit Array(int);

答案 1 :(得分:0)

主要问题

无论您的代码中存在其他问题,operator[]的签名都是错误的:

Array Array::operator[] (int i){
     ...
}

你不会在这里返回数组元素!您将返回一个全新的数组。因此,在您的错误语句中,将构造一个新的临时数组,并在封闭表达式的末尾进行破坏。

试试这个。至少它不会立即崩溃:

int& Array::operator[] (int i){
    return arr[i];
}

崩溃的原因

不幸的是,您使用malloc()分配了arr。切勿在C ++中执行此操作,而是使用new[]。这不会导致自身崩溃。但是在你的析构函数中,你使用delete

它是malloc() / free()new / deletenew[] / delete[]任何其他组合都是未定义的行为(当临时Array被破坏时,这会导致原始代码崩溃)。

按如下方式解决问题:

Array::Array(int g = 1) :size(g) //diplomatic value for size =1
{
    arr = new int[size];
}
Array::~Array()
{
    delete[] arr;
}

它将编译并工作:online demo

其他严重问题

最后为了使事情变得更糟,原始索引操作符返回*this,从而克隆现有的Array。现在已经解决了。但是,如果您制作阵列的任何副本,则会遇到其他问题:

这将导致arr指针在两个地方使用。 gests destructed的第一个Array将使原始arr中使用的Array指针无效。任何后续解除引用其arr都将是未定义的行为。

我的在线演示没有解决,所以我强烈建议您阅读rule of 3