我从这里了解到不需要std::initializer_list分配堆内存。这对我来说很奇怪,因为您可以在不指定大小的情况下获取std::initializer_list对象,而对于数组,您始终需要指定大小。尽管初始化器列表在内部几乎与数组相同(正如帖子所暗示的那样)。
我很难理解的是,C++ 作为静态类型语言,每个对象的内存布局(和大小)必须在编译时固定。因此,每个std::array都是另一种类型,我们只是从通用模板中生成这些类型。但对于std::initializer_list,此规则显然不适用,因为接收函数或构造函数不需要考虑内存布局(虽然它可以从传递给其构造函数的参数派生)。仅当类型堆分配内存并且仅保留存储来管理该内存时,这对我才有意义。那么差异就很像std::arrayand 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";
} …Run Code Online (Sandbox Code Playgroud) 在这样的代码中:
#include <iostream>
#include <initializer_list>
#include <string>
struct A
{
A() { std::cout << "2" << std::endl; }
A(int a) { std::cout << "0" << std::endl; }
A(std::initializer_list<std::string> s) { std::cout << "3" << std::endl; }
A(std::initializer_list<int> l) { std::cout << "1" << std::endl; }
};
int main()
{
A a1{{}};
}
Run Code Online (Sandbox Code Playgroud)
为什么调用std::initializer_list<int>构造函数的规范?如果我们定义构造函数,它会产生歧义编译错误std::initializer_list<double>.这种结构的规则是什么?为什么std::initializer_list数字作为模板参数如此具体?
的建议实施std::initializer_list的标准和C ++编程语言很简单。简单我的意思是没有什么奇怪的。
但是在 Compilers 的实现中事情变得复杂std::initializer_list,例如,GCC 有一个私有构造函数 for std::initializer_list,上面有一条注释说:'编译器可以调用私有构造函数。'。在这里eerorika回答:std::initializer_list是特别的。所以我在编译器源代码中寻找它:
我不明白为什么我们需要一个特殊的私有构造函数?前段时间我想转换std::vector<T>为std::initializer_list<T>.
以下程序在 GCC 和 Clang 中编译时不会发出警告,并产生预期的输出:
#include <initializer_list>
#include <iostream>
constexpr std::initializer_list<std::initializer_list<const char*>> list = {
{"a", "b", "c"},
{"d"}
};
int main() {
for (const auto& outer: list) {
std::cout << "level:\n";
for (const auto& inner: outer) {
std::cout << " " << inner << "\n";
}
}
}
Run Code Online (Sandbox Code Playgroud)
然而,使用 MSVC,该程序根本不会产生任何输出。
根据 C++ 标准,该程序有效吗?这是 MSVC 中的错误吗?如果这不是有效的 C++ 那么为什么 GCC 或 Clang 没有发出警告?有没有更好的方法来创建constexpr内部列表没有固定大小的嵌套列表?
我已经尝试了我的G ++版本的C++ 0x初始化列表实现,但它只输出空行.
#include <initializer_list>
#include <iostream>
#include <string>
int main() {
std::initializer_list<std::string> a({"hello", "stackoverflow"});
for(auto it = a.begin(), ite = a.end(); it != ite; ++it)
std::cout << *it << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
我不知道我做错了什么.有人可以帮帮我吗?
我想将一个可变参数类型列表"实现"到相关值的initializer_list中.例如,有std::tuple几个std::integral_constant<T, x>得到一个std::initializer_list<T>{...}.一般情况下,我想得到一些复杂类型的initializer_list,比如std::string.
但是下面这个简单的例子让我在Clang编译时崩溃了(虽然它适用于GCC,至少在Coliru上),所以我怀疑UB(或Clang中的bug):
template <class... Ts>
std::initializer_list<const std::string> materialize()
{
return {
std::to_string(Ts::value)...
};
}
void print_out()
{
for (const auto & x : materialize<std::true_type, std::false_type>()) {
std::cout << x << "\n";
}
}
Run Code Online (Sandbox Code Playgroud)
那么,这样的代码合法吗?在C++ 11/14/17中?
根据 cppreference.com,std::initializer_lists 具有constexpr 构造函数和constexpr 大小方法(C++14 起)。
尽管我使用的编译器似乎同意 constexpr 初始值设定项列表的大小确实是 constexpr,但在某些情况下,它不相信我的列表是 constexpr。由于 std::initializer_lists 可能涉及一些“编译器魔法”,我开始想知道 constexpr 是否不适用于它们,其方式与适用于非魔法对象的方式完全相同。
我跳到 Compiler Explorer 上,发现主要编译器在这个主题上并不一致。
那么以下四种情况的正确行为(根据标准)是什么?
#include <initializer_list>
using size_type = std::initializer_list<int>::size_type;
template <typename T>
size_type Foo(std::initializer_list<T> const &list) {
return list.size();
}
int main() {
// 1. Example based on
// https://en.cppreference.com/w/cpp/utility/initializer_list/size
// gcc: works
// clang: no viable c'tor or deduction guide
// msvc: works
static_assert(std::initializer_list{1, 2, 3}.size() == 3);
// 2. Make a constexpr std::initializer_list<T> with T …Run Code Online (Sandbox Code Playgroud) 首先,这是一个好奇的问题,我永远不会在现实生活中编写这样的代码。
以下代码与 -O3 -std=c++14 和 -O3 -std=c++17 标志的行为不同,在 C++14 中,我得到了错误的分配,我推测是从垃圾 std::string 的复制构造:
#include<algorithm>
#include<numeric>
#include<vector>
#include<string>
#include<iostream>
using namespace std;
static auto results = std::initializer_list<string>{"1 ",
"2"};
string f() {
auto result = std::accumulate(results.begin(), results.end(), string(""));
return result;
}
int main()
{
return f().size();
}
Run Code Online (Sandbox Code Playgroud)
我的猜测是 C++17 版本比 C++14 版本保持底层数组的存活时间更长,但我发现 cppreference 上的初始化列表从 C++14 到 C++17 没有相关变化,所以我很困惑。这只是 UB 是 UB,还是语言发生了变化?
PS我知道如何解决这个问题,使用static const auto& results作品,就像之前提到的,这只是一个关于语言极端情况的问题。
我知道,我可以像这样初始化数据.
int array[3] = { 1, 2, 3 };
Run Code Online (Sandbox Code Playgroud)
甚至
int array[2][2] = { {1, 2}, {3, 4} };
Run Code Online (Sandbox Code Playgroud)
我也可以这样做 std::vector
std::vector<int> A = { 1, 2, 3 };
Run Code Online (Sandbox Code Playgroud)
假设我想写自己的课程:
class my_class
{
std::vector< int > A;
public:
//pseudo code
my_class(*x) { store x in A;} //with x={ {1, 2}, {3, 4} }
// do something
};
Run Code Online (Sandbox Code Playgroud)
是否可以编写这样的构造函数,它是如何可能的?这是什么声明
{{1, 2}, {3, 4}} 实际上在做.
我总是发现,你可以用这种方式初始化数据,但绝不是它正在做的事情.
我可以简洁地(用大括号)初始化以下 6 种情况中的 5 种:
\n| 可复制的 | 只移动的 | |
|---|---|---|
| 大批 | 是的 | 是的 |
| 标准::数组 | 是的 | 是的 |
| std::向量 | 是的 | 不 |
一种似乎不起作用的情况是尝试初始化仅移动对象的 std::vector ;无法编译,并显示消息,例如:“错误:调用 \'std::unique_ptr\' 的隐式删除复制构造函数”。
\n为什么是这样?是否有适用于这种情况的替代初始化语法?
\n下面的程序演示了。
\n/*\nclang++ -std=c++14 -W -Wall -Werror question.cc -o question\nclang++ -std=c++17 -W -Wall -Werror question.cc -o question\nclang++ -std=c++20 -W -Wall -Werror question.cc -o question\nclang++ -std=c++2b -W -Wall -Werror question.cc -o question\ng++ -std=c++14 -W -Wall -Werror question.cc -o question\ng++ -std=c++17 -W -Wall -Werror question.cc -o question\ng++ -std=c++20 -W -Wall -Werror question.cc -o …Run Code Online (Sandbox Code Playgroud) c++ ×10
c++11 ×4
c++17 ×2
c++14 ×1
c++20 ×1
clang ×1
class ×1
constexpr ×1
constructor ×1
heap-memory ×1
iterator ×1
stack-memory ×1
stdvector ×1
types ×1