【问题标题】:C++: Delete a struct?C++:删除一个结构?
【发布时间】:2011-03-01 09:20:21
【问题描述】:

我有一个包含指针的结构:

struct foo
{
    char* f;
    int* d;
    wchar* m;
}

我有一个指向这些结构的共享指针向量:

vector<shared_ptr<foo>> vec;

vec 在堆栈上分配。当它在方法结束时超出范围时,将调用其析构函数。 (对吗?)这又会调用向量中每个元素的析构函数。 (对吗?)调用delete foo 是只删除foo.f 等指针,还是实际上从堆中释放内存?

【问题讨论】:

    标签: c++ memory-management heap-memory


    【解决方案1】:
    delete foo;
    

    将删除分配给 foo 结构的内存,其中包括三个指针。但是指针本身指向的内存只有在你实现显式删除它们的析构函数时才会被删除。

    【讨论】:

    • 或者,将 f、d 和 m 更改为使用自动或共享指针。
    【解决方案2】:

    如果你已经动态分配了foo,例如:

    foo* f = new foo;
    

    然后delete f 将销毁动态分配的foo 对象,包括它包含的指针,但指针指向的任何东西,如果它们确实指向动态分配的对象或对象数组.

    如果您已将动态分配的foo 对象(即new foo 的结果)分配给shared_ptr(假设为tr1 或boost),那么当最后一个引用该对象的shared_ptr 超出范围时delete 将在最初由 new foo 返回的指针上自动调用。您不必手动执行此操作。

    如果您的对象 (foo) 包含指向它拥有的动态分配对象的指针(因此需要在 foo 的生命周期结束时解除分配),那么强烈建议您编写析构函数来解除分配这些对象以正确的方式(这取决于它们的分配方式)。

    编写析构函数后,您需要考虑是否需要编写复制构造函数和复制赋值运算符。当您使用共享指针向量时,您可能会决定不应复制您的对象。如果是这样,您可以将它们声明为私有且无需提供实现。

    你还应该考虑一个或多个构造函数来确保你的指针成员被初始化。如果指针成员从未被初始化,那么如果它们在foo 的生命周期内没有被分配,那么它们既不会为空,也不会指向有效的对象,这可能会导致析构函数出错。

    【讨论】:

      【解决方案3】:

      它只删除指针。

      【讨论】:

        【解决方案4】:

        如果f 是堆栈分配的,则不要调用delete f 其中f 是foo 类型的对象。如果地址存储在共享指针中,您也不要在类型为foo 的堆分配对象上调用delete f。当最后一个引用被释放时,shared_ptr 对象将为您调用delete

        由于您的向量存储智能指针,因此当您的向量超出范围时它们也会超出范围,并且将调用 foo 析构函数并释放相关的内存。 foo 的内存只有 3 个指针大小。不是那些指针包含的内容。

        如果foo 的成员是堆分配的,那么您将需要单独分配delete。例如,如果它们指向的内存不在对象之间共享,则可能在 foo 析构函数中。


        当它在方法结束时超出范围时,将调用其析构函数。 (对吧?)

        没错。

        这将依次调用向量中每个元素的析构函数。 (对吧?)

        没错。智能指针的析构函数。

        或者它实际上是从堆中释放内存吗?

        它调用智能指针的析构函数,如果没有更多对该指针的引用,则它包含的对象将被删除并释放其内存。

        【讨论】:

          【解决方案5】:

          您的问题中似乎存在一些术语混淆。向量的析构函数将调用 shared_ptr 元素的析构函数,而后者又会在内部对其存储的指针执行 delete(如有必要)。

          调用delete foo,其中foo是指向struct foo的指针,会调用struct foo的析构函数,然后释放*foo占用的内存。

          上述struct foo 的析构函数完全没有任何作用。这是微不足道的。 If 不会尝试释放struct foo::f 或任何其他成员指向的内存。为什么会呢?它不知道也不知道是否应该释放该内存。

          事实上,因为struct foo::~foo 是微不足道的,编译器通常甚至不会尝试调用它。

          【讨论】:

            【解决方案6】:

            当 [vec] 在方法结束时超出范围时,将调用其析构函数。 (对吧?)
            正确

            这将依次调用向量中每个元素的析构函数。 (对吧?)
            正确,这将删除容器中的 shared_ptr 元素,如果它们是最后一个元素,则它们也将共享它们。

            是否调用 delete foo ...?
            你不能删除 foo,它是一个结构。您可以删除 foo 的一个实例。
            调用 delete 调用析构函数并为 foo 结构释放内存。

            foo 析构函数是只删除诸如 foo::f 之类的指针,还是实际上从堆中释放内存?
            这取决于析构函数,在这种情况下,您有一个默认析构函数,因此...
            不,在下面的示例代码中,您可以看到与 foo 关联的默认析构函数无法自动清除任何指针引用项的一些原因。

            {
             char ca='a', *cb=new char;
             int *i = (int*)malloc(sizeof(int));
             foo a;
             shared_ptr<foo> b = new foo();
             a.f = &ca;
             a.d = i;
             b.f = cb;
            }
            

            【讨论】:

              猜你喜欢
              • 2011-05-07
              • 1970-01-01
              • 2021-03-27
              • 2018-04-09
              • 1970-01-01
              • 2017-05-30
              • 1970-01-01
              • 1970-01-01
              • 2021-09-07
              相关资源
              最近更新 更多