【问题标题】:Constructors, destructors and pointers (and vectors and arrays and delete and that)构造函数、析构函数和指针(以及向量和数组以及删除等)
【发布时间】:2012-07-18 02:08:07
【问题描述】:

时髦的标题,但老实说,我想不出比这更好的人了,抱歉:(

在尝试使用指针时,我遇到了这个问题,我需要帮助来理解它。基本上,我创建了一个指向对象的指针向量。删除向量中的指针时,我希望原始对象也被删除。他们是一回事吗?

这就是我认为我在下面的代码中所做的事情,我创建了一个动态分配的数组,然后我将指向该数组一半元素的指针放入指针向量中。 testDestructor 类的每个对象的每一步都知道它是在哪个“顺序”中创建的,它们都通过静态整数分配了一个递增的数字。

然后我 pop_back 并删除向量中的所有指针。我只使用 pop_back 是因为我想看看它们是否被矢量类删除,显然它们没有,但是如果我在那里遗漏了一些东西,那就别想了。重要的是我删除了它。

现在,我期望发生的是这也会删除数组的相应元素。这是应该发生的,因为向量和数组元素指向内存中的相同位置。即,应该调用析构函数。

所以当我删除数组时,我希望要么只有 5 个元素被删除,要么发生运行时错误(我之前尝试删除已经被删除的指针时发生过这种情况,但是可能是一个不同的场景idk)。也就是说,我希望只有析构函数应该只被调用五次。

但是,事实并非如此。构造函数被调用了 10 次,而析构函数被调用了 15 次。我错过了什么?我是否缺少构造函数(我只知道默认构造函数和复制构造函数,还有更多),还是其他?因为,在我看来,当析构函数消失时,对象也就消失了。

如果代码过多,请见谅:

testDestructor.h:

#ifndef TESTDESTRUCTOR_H
#define TESTDESTRUCTOR_H

class testDestructor
{
public:
   testDestructor();
   testDestructor(const testDestructor &);
   ~testDestructor();

   static int maxTest;
   int test;
};

#endif

testDestructor.cpp:

#include "testDestructor.h"
#include <iostream>

using namespace std;

int testDestructor::maxTest = 0;

testDestructor::testDestructor()
{
   test = maxTest++;
   cout << "testDestructor nr " << test << " created successfully\n";
}

testDestructor::testDestructor(const testDestructor &destructorToCopy)
{
   test = maxTest++;
   cout<< "testDestructor nr " << test << " created successfully (using the copy constructor\n";
}
testDestructor::~testDestructor()
{
  //maxTest--;
   cout << "testDestructor " << test << " destroyed successfully\n";
}

main.cpp:

#include <iostream>
#include "testDestructor.h"
#include <vector>
using namespace std;

int main()
{
   cout << "   creating pointer array:\n\n";
   testDestructor *testPtr = new testDestructor[10];

   cout << "   intitiating vector\n\n";
   vector<testDestructor*> testVct;


   for (int i = 0; i < 5; i++)
   {

      cout << "   pushing back vector " << i << ":\n";
      testVct.push_back(testPtr + i);
      cout << "testDestructor " << testVct[i]->test << " pushed back\n";
   }
   cout << "\n";

   for (int i = 4; i >= 0; i--)
   {
      cout << "   popping back vector " << i << ":\n";
      cout << "testDestructor " << testVct[i]->test << " popped back\n";

      delete testVct[i];
      testVct.pop_back();

   }
   cout << "\n";

   cout << "   deleting pointer array\n\n";
   delete [] testPtr;
}

【问题讨论】:

  • 确实,既然我们对行为的原因有了提示,您愿意缩短问题吗?这是其他人受益的唯一方式。
  • 经验法则:每个new 一个delete,每个new[] 一个delete[]。你有:一个new[]、一个delete[]和五个deletes。
  • 我不知道如何缩短问题tbh。我真的很想(而且我确实意识到这很多),但我真的不知道怎么做,抱歉。
  • @PutBoy:就像你会写一个错误报告一样:1.问题的简要描述,2.最小的设置(代码很好,但不需要将它分成三个文件;还有例如,可以通过内联方法来缩短它),3. 观察到的和预期的行为,4. 你做了什么来理解问题,你的想法等等。你可能想把代码移到最底层。 简洁是一种美德

标签: c++ pointers constructor destructor


【解决方案1】:

当删除向量中的指针时,我期望原来的 对象也被删除。他们是一回事吗?

不,它们不一样,您的术语“删除指针”意味着您需要重新阅读有关 C++ 中指针的一些基本内容。

new 创建事物,并返回指向它所创建事物的指针。 delete 销毁事物并传递一个指向要销毁的事物的指针。指针没有改变——它只是在删除后没有指向任何有用的地方。

您要做的是delete 使用new[] 创建的对象数组中的单个对象。那根本做不到。您只能使用 delete[] 删除整个批次。如果您想拥有可单独删除的对象,请使用std::vector&lt;TestDestructor&gt;。

【讨论】:

  • ...但这可能需要一个副本甚至是移动构造函数。
  • True - 但不是在给出的简单示例类中;-)
  • 请注意在我的评论中小心使用 might ;-)
  • 我认为我不需要重新阅读,而是阅读;P 我写这段代码是有原因的,我想了解 new 和 delete 关键字。发布后我检查了不同指针的地址,不,它们不指向同一个地址,你说的。不过我还是不明白为什么。
【解决方案2】:

这里的问题是testDestructor 的前五个实例被删除了两次:一次是delete testVct[i],另一次是delete [] testPtr;。

第一个delete是错误的。

对象由testVct拥有,因此它们的销毁只能通过testVct 的delete[]ion 进行。只有在 new 分配的单个对象时,您才能delete。

【讨论】:

  • 这是不正确的。您可以通过任何指向它的指针来删除一个对象。由程序员确保对象只被删除一次。
  • @Code-Guru 您可以通过任何指针销毁对象,但您只能删除已分配的内存。
  • 啊...testVct 是一个指针向量,但指针 testPtr 指向一个对象数组。 那肯定会产生很大的不同,因为没有一个对象是用new分配的。我想我应该在开口之前更仔细地查看代码。
【解决方案3】:

operator delete[] 将在删除数组本身之前调用数组中项的析构函数。如果您希望手动删除数组中的某些项目,您需要在之后将其数组索引值设置为NULL。在同一个对象上调用析构函数两次是未定义的行为,希望对你来说会很糟糕。

【讨论】:

  • 无法从数组中删除类类型的对象。
【解决方案4】:

首先,让我们看看你的变量声明:

testDestructor *testPtr = new testDestructor[10];
vector<testDestructor*> testVct;

这表示 testPtr 是指向 testDestructor 类型对象的指针,而 testVct 是指向 testDestructor 类型对象的指针向量。

此外,您使用 new 运算符分配一个 testDestructor 对象数组,并分配 testPtr 中第一个元素的地址。现在 testPtr 可以用作一个数组来 testDestructor objects。

请注意,您没有为任何单独的 testDestructor 对象分配内存。这意味着您删除指向数组中对象的任何指针都会导致未定义的行为。另一方面,在 testPtr 上使用 delete[] 来释放数组是允许的。

这里的一般规则是每个 delete 或 delete[] 必须有一个匹配的 new 或 new[],反之亦然。

【讨论】:

    【解决方案5】:

    第一

    在我的测试中,这个程序将核心转储在'delete testVct[i];'

    我的g++版本是4.1.6

    也许你可以初始化 testPtr:

    testDestructor *testPtr[10];
    for(int i=0;i<10;i++)
        testPtr[i] = new testDestructor;
    

    第二

    你删除了一个指针两次 1)删除testVct[i]; 2) 删除 [] testPtr;

    【讨论】:

      猜你喜欢
      • 2012-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多