【问题标题】:C++ Allocate Memory Without Activating ConstructorsC++ 在不激活构造函数的情况下分配内存
【发布时间】:2011-06-02 08:32:54
【问题描述】:

我正在从一个文件中读取值,我将在读取它们时将其存储在内存中。我在这里读到,在 C++ 中处理内存位置的正确方法是始终使用 new/delete,但是如果我愿意:

DataType* foo = new DataType[sizeof(DataType) * numDataTypes];

然后这将为每个创建的实例调用默认构造函数,我不希望这样。我打算这样做:

DataType* foo;
char* tempBuffer=new char[sizeof(DataType) * numDataTypes];
foo=(DataType*) tempBuffer;

但我认为这将是某种类型不安全的东西。那我该怎么办?

现在在研究这个问题时,我看到有些人说数组不好,向量好。我试图更多地使用数组,因为我认为我是一个坏孩子,用(我认为的)较慢的向量填充我的程序。我应该用什么???

【问题讨论】:

  • 来吧,你在担心效率,而你的第一行代码不正确!
  • 如果您没有性能问题,您应该选择最简单、最安全的解决方案

标签: c++ memory-management


【解决方案1】:

使用向量!!!由于您知道元素的数量,因此请确保先保留内存(在插入元素之前调用 myVector.reserve(numObjects)。)。

这样做,您将不会调用类的默认构造函数。

所以用

std::vector<DataType> myVector; // does not reserve anything
...
myVector.reserve(numObjects); // tells vector to reserve memory

【讨论】:

  • 向量通常是一个不错的选择,但它们仍然不允许您调用您选择的构造函数。矢量元素始终是复制构造的。
  • 真的!然后,您可以根据需要使用指向对象的智能指针向量(因此将调用智能指针的复制构造函数)。
  • @Ben Voigt:在 C++0x 中,emplace_back 不允许您使用您选择的构造函数吗?
  • @Matthieu:正确,C++0x 最终会填补这个缺失的部分(我使用将来时,因为我认为这个功能还没有在任何编译器中实现)。
【解决方案2】:

您可以使用::operator new 分配任意大小的内存块。

DataType* foo = static_cast<DataType*>(::operator new(sizeof(DataType) * numDataTypes));

在这里使用::operator new 而不是malloc 的主要优点是它会引发故障,并且会与任何new_handlers 等集成。您需要使用::operator delete 清理内存

::operator delete(foo);

常规的new Something 当然会调用构造函数,毕竟这就是new 的意义所在。

避免额外构造(例如默认构造函数)或出于性能原因推迟它们是一回事,完全跳过任何构造函数是另一回事。我觉得你有类似的代码

DataType dt;
read(fd, &dt, sizeof(dt));

如果你这样做,你已经把类型安全抛到了窗外。

你为什么试图通过不调用构造函数来完成?

【讨论】:

  • 像问题已经提到的那样直接调用::operator newnew char[] 有什么优势?
  • @Ben Voigt,主要在这种情况下传达意图。您不是在尝试创建一个 `char's 数组,而是在分配一些内存。第二个问题是 IIRC 数组 new 会将 POD 初始化为 0,这会带来一些轻微的开销。
  • 似乎是默认初始化的,因为 char 不是类类型,所以什么都不做。不幸的是,我面前只有 C++0x 草案标准,这绝对是正在改变的事情之一(在 C++0x 中,新数组允许使用括号初始化器)。
【解决方案3】:

您可以使用new char[] 分配内存,为数组中的每个元素调用所需的构造函数,然后一切都将是类型安全的。阅读What are uses of the C++ construct "placement new"?

这就是std::vector 在底层的工作方式,因为它为提高效率分配了一点额外的内存,但在实际需要它们之前不会在额外的内存中构造任何对象。

【讨论】:

    【解决方案4】:

    您应该使用矢量。它将允许您一个接一个地构建其内容(通过push_back 等),这听起来就像您想要做的那样。

    【讨论】:

      【解决方案5】:

      如果您不会在向量末尾以外的任何地方插入新元素(因为向量的元素存储在连续的内存块中),我认为您不应该关心使用向量的效率。

      【讨论】:

        【解决方案6】:
        vector<DataType> dataTypeVec(numDataTypes);
        

        正如您所知道的,您的第一行包含一个错误(无需乘以 sizeof)。

        【讨论】:

        • 您可能希望在声明未调用默认构造函数之前对其进行测试。 (它是,一次,然后复制构造函数被称为numDataTypes 次。)
        【解决方案7】:

        基于其他人所说的,如果您在管道输入整数文本文件时运行该程序,该文件将填充以下类的数据字段,例如:

        ./allocate < ints.txt
        

        那么你可以这样做:

        #include <vector>
        #include <iostream>
        
        using namespace std;
        
        class MyDataType {
        public:
          int dataField;
        };
        
        
        int main() {
        
          const int TO_RESERVE = 10;
        
          vector<MyDataType> everything;
          everything.reserve( TO_RESERVE );
        
          MyDataType temp;
          while( cin >> temp.dataField ) {
            everything.push_back( temp );
          }
        
          for( unsigned i = 0; i < everything.size(); i++ ) {
            cout << everything[i].dataField;
            if( i < everything.size() - 1 ) {
              cout << ", ";
            }
          }
        }
        

        对于我来说,有 4 个整数的列表,给出:

        5, 6, 2, 6
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-01-06
          • 1970-01-01
          • 1970-01-01
          • 2020-11-27
          • 2015-03-12
          • 2016-07-29
          • 1970-01-01
          相关资源
          最近更新 更多