【问题标题】:Is it correct to create a class instance through malloc and instead placement new?通过 malloc 创建类实例而不是放置 new 是否正确?
【发布时间】:2015-03-29 10:20:29
【问题描述】:

这是一个类。

class A
{
public:
A()
private:
int m_a;
};

我们能否创建一个类的对象,而不是放置运算符new 并使用malloc,如下所示:

void* a = malloc(sizeof(A)); // allocate raw memory 
A* obj = reinterpret_cast< A* > ( a ); // assign to the adress
a->A() // call the constructor

正确吗?如果不是,我们可以使用malloc 构造一个对象而不是放置new(使用其他一些C 技术)吗?

【问题讨论】:

  • 这还能编译吗?
  • @πάνταῥεῖ 不,invalid use of A::A
  • 调用构造函数的代码是new(obj) A,而不是a-&gt;A()。是的,这应该可行。
  • 我不知道。我需要了解可以通过 malloc 创建实例而不是放置新实例,即使用一些 C 技术?
  • 你不能,这是唯一的办法

标签: c++ object malloc dynamic-memory-allocation placement-new


【解决方案1】:

malloc 获取原始内存后,您需要使用placement new

class S
{};
...
void *mem = malloc(sizeof(S));
S* s = new (mem) S(); //this is the so called "placement new"

然后显式调用它的析构函数。

s->~S();
free(mem);

【讨论】:

    【解决方案2】:

    让我们稍微澄清一下术语。 'Placement new' 是调用构造函数的方法,它不分配内存。常规 new 更类似于 malloc,因为它分配内存。

    在 C++ 中使用 malloc 的正确方法是 malloc 并然后使用placement new。

    void* a = malloc(sizeof(A)); // allocate raw memory 
    A* obj = reinterpret_cast< A* > (a);
    new(obj) A(); // placement new syntax runs the constructor of A()
    

    或者进一步简化:

    void* a = malloc(sizeof(A)); // allocate raw memory 
    A* obj = new(a) A(); // placement new syntax runs the constructor of A()
    

    但是,(通常)没有理由这样做。如果你需要使用特定的分配器,你可以定义一个自定义的 operator new 重载。

    【讨论】:

    • 我会将第二行和第三行合并到A* obj = new(a) A(); 中,这样可以避免将reinterpret_cast 转换为无效类型(从malloc 返回的指针不指向@987654326 @ 直到 A 被构造)。
    • 在你的代码中你使用了新的。问题是,如何使用 new(obj) A() 来做 sush 事情?
    • @Վարդան Գրիգորյան :您误会了:在这种情况下,新称为放置新,它不分配内存。它只调用 A() 的构造函数。
    • @ՎարդանԳրիգորյան:不使用 new 就无法直接调用构造函数。 (或者换一种说法,placement new 直接调用构造函数的C++机制)。
    • 简化版第二行不应该是A* obj = new(a) A();吗?
    【解决方案3】:

    注意,malloc 返回的地址与 8 字节对齐。如果你的班级只有一个

    char a[6];
    

    成员你浪费了 2 个字节(如果你只有 1 个字符或 1 个布尔值,你将浪费 7 个字节),而如果你有一个

    v4si a;
    

    SIMD 指令的 4 字节向量,您可能有错误的对齐方式,需要额外的指令才能正确地重新对齐。

    不浪费内存:

    class TinyClass{
        char c[3];
    public:
        TinyClass( char c1, char c2, char c3){
            c[0] = c1; c[1] = c2; c[2] = c3;
        }
    };
    

    基本上你必须一次创建多个对象(但它们也必须同时销毁,所以这可能不适合你)

    #include <new> //not needed if you already include any STL header
    
    int number_of_items = 6;
    void* a = malloc(sizeof(TinyClass)*number_of_items);
    TinyClass * Ptr = reinterpret_cast< TinyClass* > (a);
    for(int i=0; i<number_of_items; i++)
        new(&Ptr[i]) TinyClass('a','b','c');
    
    //later
    for(int i=0; i<number_of_items; i++)
        Ptr[i].~TinyClass();  //destructor
    Ptr = NULL; // or Ptr = nullptr; if you have c++11
    free(a);
    

    .

    强制对齐大于 8 个字节:

    C++ possible implementation of aligned malloc

    如果你不介意性能或内存浪费,当然忘了我说的 ^^,因为那是有点臃肿的代码。

    在 C++ 中也一样吗?不完全是,在 c++ 中使用“new”会返回一个至少与所需内容对齐的指针,但不能保证实现不会有更大的对齐)

    【讨论】:

      猜你喜欢
      • 2015-05-22
      • 2014-11-29
      • 1970-01-01
      • 2018-05-28
      • 2019-02-12
      • 1970-01-01
      • 2010-10-22
      相关资源
      最近更新 更多