我从这里了解到,std::initializer_list
不需要分配堆内存。这让我感到非常奇怪,因为您可以接收一个std::initializer_list
对象而无需指定其大小,而对于数组,您总是需要指定大小。虽然这篇文章提到 initializer list 内部实现几乎与数组相同。
我很难理解的是,C++作为一种静态类型语言,每个对象的内存布局(和大小)必须在编译时确定。因此,每个std::array
都是另一种类型,我们仅从共同的模板生成这些类型。但是对于std::initializer_list
,这个规则显然不适用,因为接收函数或构造函数不需要考虑内存布局(虽然它可以从传递给其构造函数的参数中推导出来)。只有当类型分配堆内存并且仅保留存储器以管理该内存时,这才对我有意义。然后差异将类似于std::array
和std::vector
,对于后者,您也不需要指定大小。
然而,如我的测试所示,std::initializer_list
不使用堆分配:
#include <string>
#include <iostream>
void* operator new(size_t size)
{
std::cout << "new overload called" << std::endl;
return malloc(size);
}
template <typename T>
void foo(std::initializer_list<T> args)
{
for (auto&& a : args)
std::cout << a << std::endl;
}
int main()
{
foo({2, 3, 2, 6, 7});
// std::string test_alloc = "some string longer than std::string SSO";
}
这怎么可能?我能为我的类型编写类似的实现吗?那样可以在进行编译时不会炸掉我的二进制文件,真是太好了。
编辑:我应该指出我想问的问题不是编译器如何知道应该用什么大小来实例化初始化列表(可以通过模板参数推导来实现),而是它与所有其他初始化列表实例化不同的方式(因此您可以将大小不同的初始化列表传递给同一个函数)。
std::initializer_list
。 - NathanOliverstd::initializer_list
中的值就像底层的简单数组一样。如果你检查你的示例生成的汇编代码(https://godbolt.org/z/vEoc46Pn9),你会发现你的数组在二进制文件中。你不能实现它,因为`std::initializer_list`是一个特殊的类,与编译器"绑定"。就像`constexpr construt_at`一样,你也无法实现它... - simreint a[] = {1,2,3};
中您不需要指定大小 - 编译器会自动识别。 - molbdniloconst char s[] = "Hello World";
如何与const char *s = "Hello World";
一样工作,且s
会衰变为一个简单的指针。 - Goswin von Brederlow