【问题标题】:C++: allocate block of T without calling constructorC++:在不调用构造函数的情况下分配 T 块
【发布时间】:2010-03-04 21:44:00
【问题描述】:

我不想调用构造函数。我正在使用新展示位置。

我只想分配一块T。

我的标准做法是:

T* data = malloc(sizeof(T) * num);

但是,我不知道 (data+i) 是否是 T 对齐的。此外,我不知道这是否是正确的“C++”方式。

如何在不调用构造函数的情况下分配 T 块?

【问题讨论】:

  • 为什么不想调用构造函数呢?如果是因为你的构造函数正在做你并不总是想做的工作,你可能会考虑将这项工作转移到一个单独的 init() 方法中。
  • 例如,std::vector 执行此操作(分配内存但尚未构造对象)。

标签: c++ memory-management


【解决方案1】:

首先,您没有分配“T* 块”。您正在分配一个“T 块”。

其次,如果您的T 具有非平凡的构造函数,那么在构造元素之前,您的块并不是真正的“T 块”,而是一块原始内存。在这里涉及T 毫无意义(除了计算大小)。 void * 指针更适合原始内存。

要分配内存,你可以使用任何你喜欢的东西

void *raw_data = malloc(num * sizeof(T));

void *raw_data = new unsigned char[num * sizeof(T)];

void *raw_data = ::operator new(num * sizeof(T));

std::allocator<T> a;
void *raw_data = a.allocate(num);
// or
// T *raw_data = a.allocate(num);

稍后,当您实际构造元素时(如您所说,使用placement new),您最终将获得T * 类型的有意义的指针,但只要内存是原始的,使用T * 几乎没有感觉(虽然这不是错误)。

除非您的T 有一些特殊的对齐要求,否则上述分配函数返回的内存将正确对齐。

您实际上可能想看看 C++ 标准库提供的内存实用程序:std::allocator&lt;&gt;allocateconstruct 方法,以及 uninitialized_fill 等算法,而不是尝试重新发明轮子。

【讨论】:

  • 我认为 std::allocator 是“最 C++”的方式
  • 如何使用这种方法解除分配(调用析构函数)?
  • @André Puel:你做的一切都是相反的。首先,您手动一一调用析构函数(C++ 中有析构函数调用的语法)。然后你只需free 内存(如果它是malloced),或者使用另一个适当的原始内存释放函数。
  • 我的意思是,如果您在 T* 上调用 delete[],就会发生不好的事情。如果你把这个 T* 给别人并说“你拥有这个 T*”,这个别人可能会调用 delete[]。请在您的回答中包含此警告。
  • @André Puel:不。这是一个完全不同的问题,与所提出的问题无关。这就像在每个甚至提到除法运算符的答案中都包含有关被零除的危险的警告。问题是关于自定义分配的一些细节,而不是自定义分配的基础知识。
【解决方案2】:

malloc 的返回值与任何类型对齐,所以这不是问题。

通常在 C++ 中,::operator new 将是首选方式。您也可以考虑使用Allocator&lt;T&gt;,它提供了一些额外的灵活性(比如能够轻松切换分配器。

【讨论】:

    【解决方案3】:

    T* data = reinterpret_cast&lt;T*&gt;(operator new(sizeof(T) * num));

    或者只使用std::vector&lt;T&gt;,不用担心这些低级内存细节;)

    【讨论】:

    • 我认为如果 T 不是 POD 类型,那么这会导致未定义的行为。
    • vector 将为每个 T 调用默认构造函数。
    猜你喜欢
    • 2011-06-02
    • 1970-01-01
    • 2014-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-11
    相关资源
    最近更新 更多