首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++布局新、继承和析构函数

C++布局新、继承和析构函数
EN

Stack Overflow用户
提问于 2015-05-20 15:47:32
回答 1查看 1.5K关注 0票数 4

伙计们,

当在类层次结构上使用allocation new时,基类必须执行去分配。否则,将对取消分配的对象调用基类析构函数.我希望能够从派生类执行去分配。因此,我开放的想法和建议!(注意:我没有结婚安置-新的,但我想有自定义内存管理,而不是新/删除)。

请在下面找到代码示例:

代码语言:javascript
复制
#include <cstdint>
#include <cstdio>
#include <new>

class CParent
{
public :
    CParent() {
        printf("CParent()\n");
    }

    virtual ~CParent() {
        printf("~CParent()\n");
    }
};

class CAllocator
{
private :
    void Free(uint8_t *buffer) {
        printf("CAllocator::Free(%p)\n", buffer);
        delete [] buffer;
    }

    class CChild : public CParent
    {
    public :
        CChild(CAllocator &allocator, uint8_t *buffer)
            : mAllocator(allocator), mBuffer(buffer)
        {
            printf("CChild()\n");
        }

        ~CChild() {
            printf("~CChild()\n");
            mAllocator.Free(mBuffer);
        }

    private :
        CAllocator &mAllocator;
        uint8_t *mBuffer;
    };

public :
    CParent *Alloc() {
        uint8_t *buffer = new uint8_t[sizeof(CChild)];
        printf("CAllocator::Alloc() = %p\n", buffer);
        return new (buffer) CChild(*this, buffer);
    }
};

int main()
{
    CAllocator allocator;
    CParent *object = allocator.Alloc();

    // NB: Can't do `delete object` here because of placement-new
    object->~CParent();
    return 0;
}

它提供了以下输出:

代码语言:javascript
复制
CAllocator::Alloc() = 0x2001010
CParent()
CChild()
~CChild()
CAllocator::Free(0x2001010)
~CParent()

所以在内存释放后调用~CParent() ..。非常感谢你的帮助!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-05-20 16:52:47

你把下面的概念混合在一起,让我觉得你不清楚它们应该是什么:

  1. 基类/派生类析构函数。
  2. 放置new算子
  3. 内存分配和分配。

当您使用普通的旧operator new分配对象时,会发生两件事:

  1. 内存分配给对象。
  2. 对象的构造函数(对于具有构造函数的类)被调用。

当对由operator delete返回的指针调用operator new时,会发生两种情况:

  1. 对象的析构函数被调用。
  2. 内存被取消分配。

使用placement new运算符时,必须:

  1. 在调用placement new运算符之前分配内存。
  2. 在调用new时使用预先分配的内存。调用类的构造函数来初始化对象。

对于这些对象,您必须:

  1. 显式调用析构函数。
  2. 使用与内存分配方式相匹配的方法来取消内存分配。如果使用operator new char[size];分配内存,则使用delete [] ptr;来释放内存。如果使用malloc(size)分配内存,则使用free(ptr)来释放内存。

为了保持代码的整洁,您应该将以下内容分开:

  1. 分配和取消内存分配的责任。
  2. 调用构造函数和析构函数的责任。

在您发布的代码中,类CChild似乎是不干净的。还不清楚它是用于帮助您管理内存的面向类的用户还是帮助您管理内存的助手类。

如果您想让它成为一个面向类的用户,我会将代码重构为:

代码语言:javascript
复制
#include <cstdint>
#include <cstdio>
#include <new>

class CParent
{
   public :
      CParent() {
         printf("CParent()\n");
      }

      virtual ~CParent() {
         printf("~CParent()\n");
      }
};

class CChild : public CParent
{
   public :
      CChild()
      {
         printf("CChild()\n");
      }

      ~CChild() {
         printf("~CChild()\n");
      }

   private :
};

class CAllocator
{
   public :
      void Free(uint8_t *buffer) {
         printf("CAllocator::Free(%p)\n", buffer);
         delete [] buffer;
      }


      uint8_t *Alloc(size_t size) {
         uint8_t *buffer = new uint8_t[size];
         printf("CAllocator::Alloc() = %p\n", buffer);
         return buffer;
      }
};

int main()
{
   CAllocator allocator;
   uint8_t *buffer = allocator.Alloc(sizeof(CChild));

   CParent* object = new (buffer) CChild;

   object->~CParent();

   allocator.Free(buffer);

   return 0;
}

如果您打算将CChild用作管理内存的助手类,那么首先要做的是确保CAllocator::Alloc()CAlloctor::Free()是对称的。由于Alloc()返回指向CParent的指针,因此需要更改Free()以接受指向CParent的指针并对其执行正确的操作。下面是我认为代码应该是什么样子:

代码语言:javascript
复制
#include <cstdint>
#include <cstdio>
#include <new>

class CParent
{
   public :
      CParent() {
         printf("CParent()\n");
      }

      virtual ~CParent() {
         printf("~CParent()\n");
      }
};

class CAllocator
{
   private :

      class CChild : public CParent
      {
         public :
            CChild(uint8_t *buffer) : mBuffer(buffer)
            {
               printf("CChild()\n");
            }

            ~CChild() {
               printf("~CChild()\n");

               // The object has ownership of the buffer.
               // It can deallocate it.
               delete [] mBuffer;
            }

         private :
            uint8_t *mBuffer;
      };

   public :

      // Make Alloc and Free symmetric.
      // If Alloc() returns a CParent*, make sure Free()
      // accepts the same value and does the right thing
      // with it.

      CParent *Alloc() {
         uint8_t *buffer = new uint8_t[sizeof(CChild)];
         printf("CAllocator::Alloc() = %p\n", buffer);

         // Transfer the ownership of buffer to CChild
         return new (buffer) CChild(buffer);
      }

      void Free(CParent* object) {
         printf("CAllocator::Free(%p)\n", object);
         object->~CParent();
      }


};

int main()
{
   CAllocator allocator;

   CParent *object = allocator.Alloc();
   allocator.Free(object);

   return 0;
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30354497

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档