如何在不初始化每个元素的情况下为数组保留空间
How can you reserve space for an array without initializing each element?
下面的代码将使用默认的Foo构造函数构造10个Foo对象的数组:
Foo foo[10];
但我不想这样做,我有 Havy Foo 构造函数,稍后我将一个接一个地再生所有 Foo 对象并分配(复制)它到Foo数组的元素,所以没有意义要初始化数组,我只想为它保留空间并稍后设置它元素。就像
在int foo[10]
当 foo 的元素在没有 ={} 的情况下不会被初始化时。 如何在不使用 std 命名空间的情况下执行此操作(我将在不支持 std 的 PC 和 CUDA 上使用代码)?
你可以做所有好的动态容器做的事情:单独的内存分配和对象构造。
// allocate memory
char * space[10 * sizeof(Foo)];
// make sure it's aligned for our purposes
// see comments; this isn't actually specified to work
assert(reinterpret_cast<uintptr_t>(space) % alignof(Foo) == 0);
// populate 4th and 7th slots
Foo * p = ::new (space + 3 * sizeof(Foo)) Foo('x', true, Blue);
Foo * q = ::new (space + 6 * sizeof(Foo)) Foo('x', true, Blue);
// ...
// clean up when done
q->~Foo();
p->~Foo();
使用自动存储时,棘手的部分是使存储对齐到适合数组元素类型对齐的地址。有几种方法可以实现此目的;我以后会对它们进行讨论:
std::align
(感谢@Simple):char large_space[10 * sizeof(Foo) + 100]; std::size_t len = sizeof large_space; void * space_ptr = large_space; Foo * space = static_cast<Foo *>(std::align(alignof(Foo), 10 * sizeof(Foo), space, len)); assert(space != nullptr); // construct objects in &space[i]
用
alignas
限定space
的定义alignas(Foo) char space[10 * sizeof(Foo)];
使
space
成为一系列合适的std::aligned_storage
专业化(感谢@RMF)std::aligned_storage<sizeof(Foo), alignof(Foo)>::type space[10]; Foo *p = new (&space[3]) Foo('x', true, Blue); Foo *q = new (&space[6]) Foo('x', true, Blue);
最简单的方法是使用 std::vector
:
std::vector<Foo> foo;
如果需要,可以调用foo.reserve(10)
来分配内存。如果你有 C++11,你可以使用 foo.emplace_back(/*args*/)
将对象直接创建到数组中,无需复制。
如果您不想/不能使用std::vector
,您可以手动执行此操作:
unsigned char foo[10 * sizeof(Foo)];
然后要构造对象,请使用放置 new:
int x = ...;
Foo *fooX = new (foo[x * sizeof(Foo)) Foo(/*args to the constructor*/);
但是,您最终将不得不手动调用析构函数:
fooX->~Foo();
但请注意,此解决方案在字节数组的对齐方面可能存在困难。您可能更喜欢使用malloc()
来确保:
unsigned char *foo = malloc(10 * sizeof(Foo));
如果你不会在数组中留下漏洞,你可以简单地将std::vector
与reserve
和push_back
一起使用。
如果你想在数组中出现孔...您可以使用一些分配器获得大小合适且对齐正确的内存块,然后使用放置新等...但是您必须跟踪哪些洞被填满,哪些洞没有被填满。 boost::optional
已经做到了这一切,所以std::vector<boost::optional<Foo>>
会很好地服务并为您省去一堆麻烦。
方法是使用std::vector
std::vector<Foo> foovec;
foovec.reserve(10);
所以,有 10 个 Foo
型元素的地方,但它们还没有被构建。
此外,您可以使用placing-new
手动编写类似的东西
char* place = static_cast<char*>(::operator new(sizeof(Foo) * 10));
然后填充放置新运算符。
Foo* f1 = new (place) Foo(...);
Foo* f2 = new (place + sizeof(Foo)) Foo(...);
//
f1->~Foo();
f2->~Foo();
::operator delete(place);
我的解决方案考虑了这些约束(OP 和对不同答案的一些评论暗示):
- 我们不能使用 STL;和
- 我们想使用堆栈内存(而不是堆)。
它还考虑了其他人提到的对齐问题,鉴于 OP 被标记为 C++11,我们可以使用 C++11。
首先为未初始化它的Foo
引入存储:
union FooStorage {
Foo data;
FooStorage() {
}
template <typename... Args>
void init(Args&&... args) {
new (&data) Foo{static_cast<Args&&>(args)...};
}
~FooStorage() {
data.~Foo();
}
};
请注意,构造函数不会初始化data
但析构函数会销毁它。您必须在销毁之前初始化data
(使用 init()
)。(从OP来看,我认为它会发生,但我必须指出这种危险。
请注意,使用 { ... }
和 ( ... )
的初始化并不等效。你必须根据Foo
的构造函数做出决定。
以这种方式分配 10 Foo
秒的堆栈内存
FooStorage buffer[10];
要初始化第 i
Foo
:
buffer[i].init(/* constructor arguments */);
要使用i
-th Foo
,例如,调用它的方法do_something
:
buffer[i].data.do_something();
这是基本思想。可以做很多改进来FooStorage
。
数组boost::optional<Foo>
或 C++14 std::optional<Foo>
boost::optional<Foo> foo[10];
?
- 是默认情况下分配给char数组常量的值
- C++默认情况下,指针类型数组的元素是否保证初始化为 nullptr?
- C++数组与向量排序(在我的情况下,向量比数组慢~2.5倍(无优化))
- 如何在不使用 C++ 中的数组或函数的情况下查找 N 位数字的所有排列
- 如何在没有硬编码的情况下以C++为单位获取类数组的长度?
- 有没有一种惯用的方法可以在不存储变换或不必要地重新计算的情况下找到数组变换的最小/最大值?
- 如何在不知道大小的情况下读取文本文件并存储到数组中
- 在不工作的情况下为数组分配指针,但反过来也可以
- 在不进行排序的情况下查找数组中n个最小值的索引
- 在这种情况下,数组a会被取消分配吗
- 在不复制数据的情况下,将double数组转换为只有double成员的structs数组
- 如何在不迭代的情况下对数组中的每个元素调用方法
- 在给定元素在螺旋上的位置的情况下,在二维数组中查找元素
- 推荐的方法在不初始化值的情况下使数组类型为 std::unique_ptr?
- 在哪种情况下,C++会在编译时进行数组边界检查?
- 在这种情况下,删除指针数组期间会发生什么?
- 如何在不初始化每个元素的情况下为数组保留空间
- 在不指定大小的情况下分配数组
- 为什么两种情况下数组的大小都不相同
- 在不使用 hash_map的情况下对数组中的重复条目进行分组