考虑以下程序:
#include <stdexcept>
#include <stdio.h>
#include <memory>
#include <list>
class Foo {
public:
Foo(){
if (s_ct==0) {throw std::bad_alloc();}
--s_ct;
fprintf(stderr, "ctor %p\n", this);
}
~Foo(){
fprintf(stderr, "dtor %p\n", this);
}
private:
static int s_ct;
};
int Foo::s_ct = 2;
int main(){
try {
std::list<std::shared_ptr<Foo>> l = {
std::make_shared<Foo>(),
std::make_shared<Foo>(),
std::make_shared<Foo>()
};
} catch (std::bad_alloc&) {
fprintf(stderr, "caught exception.\n");
}
fprintf(stderr, "done.\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译如下:
[little:~] $ g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, …Run Code Online (Sandbox Code Playgroud) 在另一个主题中,@ Didmar给出了这个解决方案:
template <typename... T>
std::tuple<T...> parse(std::istream& in)
{
return std::tuple<T...>{ T(in)... };
}
Run Code Online (Sandbox Code Playgroud)
说明,
大括号初始化的使用起作用,因为大括号初始化列表中参数的求值顺序是它们出现的顺序.(强调我的)
C++标准(n3485)的相关文本是,
在braced-init-list的initializer-list中,initializer-clauses(包括pack扩展(14.5.3)产生的任何结果)按照它们出现的顺序进行评估.也就是说,与给定初始化子句相关联的每个值计算和副作用在每个值计算和副作用之前与在初始化列表的逗号分隔列表中跟随它之后的任何初始化子句相关联.[注意:无论初始化的语义如何,此评估顺序都保持不变; 例如,当initializer-list的元素被解释为构造函数调用的参数时,它适用,即使通常对调用的参数没有排序约束. - 尾注]
所以我尝试用以下代码测试它:
template<int N>
struct A
{
std::string data;
A(std::istream & stream) { stream >> data; }
friend std::ostream& operator<<(std::ostream & out, A<N> const & a)
{
return out << "A"<<N<<"::data = " << a.data;
}
};
typedef A<1> A1;
typedef A<2> A2;
template<typename ...Args>
void test(std::istream & stream)
{
std::tuple<Args...> args { Args(stream)... }; …Run Code Online (Sandbox Code Playgroud) 我很好奇初始化列表和序列点.我刚才读到初始化程序列表中的评估顺序是从左到右.如果是这样,那么评估点之间肯定会有某种序列点,我错了吗?那么说是以下有效代码?是否有任何导致其未定义的行为?
int i = 0;
struct S {
S(...) {}
operator int() { return i; }
};
int main() {
i = S{++i, ++i};
}
Run Code Online (Sandbox Code Playgroud)
任何和所有回复都表示赞赏.
如果元素std::initializer_list总是const值,为什么我们有模板方法喜欢begin()/end()和不cbegin()/cend()?这个名称(通过惯例,与例如比较std::vector)可以表明,当它们总是返回时,两种std::initializer_list方法都可以iterator返回const_iterator.
作为在讨论这个SO问题时提出的一个问题:
申报对象是否合法,可能是N3471constexpr std::initializer_list?例:
constexpr std::initializer_list<int> my_list{};
Run Code Online (Sandbox Code Playgroud)
为什么我认为它可能不合法:initializer_list必须是字面类型; 但有没有保证它是文字类型?
来自N3485的引文.
[dcl.constexpr]/9:
对象声明中使用的constexpr说明符将对象声明为const.这样的对象应具有文字类型并应初始化.
文字类型要求,[basic.types]/10,子项目类类型:
- 具有以下所有属性的类类型(第9节):
- 它有一个简单的析构函数,
- 非静态数据成员(如果有)的brace-or-equal-initializers中的每个构造函数调用和完全表达式都是一个常量表达式(5.19),
- 它是一个聚合类型(8.5.1)或者至少有一个constexpr构造函数或构造函数模板,它不是复制或移动构造函数,并且
- 它的所有非静态数据成员和基类都是非易失性文字类型.
奖励积分;)用于回答if
constexpr std::initializer_list<int> my_list = {1,2,3,4,5};
Run Code Online (Sandbox Code Playgroud)
是合法的(有参考).虽然我认为上述+ [dcl.init.list]/5涵盖了这一点
#include <iostream>
struct X {
X(std::initializer_list<int> list) { std::cout << "list" << std::endl; }
X(float f) { std::cout << "float" << std::endl; }
};
int main() {
int x { 1.0f };
X a(1); // float (implicit conversion)
X b{1}; // list
X c(1.0f); // float
X d{1.0f}; // list (narrowing conversion) ARG!!!
// warning: narrowing conversion of '1.0e+0f' from 'float' to 'int'
// inside { } [-Wnarrowing]
}
Run Code Online (Sandbox Code Playgroud)
有没有其他方法可以std::initializer_list从过载列表中删除(即,使非列表ctors更有利),而不是使用()初始化,或者至少禁止缩小转换(除了将警告变为错误)?
我使用的是使用GCC 4.8的http://coliru.stacked-crooked.com/编译器.
如果初始化列表顺序与类中的变量顺序不匹配,为什么gcc会抛出一个合适的东西呢?
class myClass
{
public:
int A;
int B;
myClass();
};
myClass::myClass() :
B(1),
A(2)
{}
Run Code Online (Sandbox Code Playgroud)
将导致:
file.h:274: warning: 'myClass::A' will be initialized after
file.h:273: warning: 'int myClass::B
file.cpp:581: warning: when initialized here
Run Code Online (Sandbox Code Playgroud)
发出这种警告有什么具体原因吗?是否存在与初始化类变量相关的风险,其顺序与在类中定义的顺序不同?
(注意,有一个问题触及了这个主题,但答案几乎是"因为它应该是这样"而没有给出任何理由,为什么应该订购,或者这有什么不对的故障 - 我会想知道为什么存在这样的限制 - 有人会举例说明它可能适得其反吗?)
我们考虑以下几点:
#include <iostream>
#include <initializer_list>
class Foo {
public:
Foo(int) {
std::cout << "with int\n";
}
};
int main() {
Foo a{10}; // new style initialization
Foo b(20); // old style initialization
}
Run Code Online (Sandbox Code Playgroud)
在运行它打印:
with int
with int
Run Code Online (Sandbox Code Playgroud)
都好.现在由于新的要求,我添加了一个构造函数,它带有一个初始化列表.
Foo(std::initializer_list<int>) {
std::cout << "with initializer list\n";
}
Run Code Online (Sandbox Code Playgroud)
现在它打印:
with initializer list
with int
Run Code Online (Sandbox Code Playgroud)
所以我的旧代码Foo a{10}被默默地打破了.a应该用a初始化int.
我理解语言语法正在考虑{10}作为包含一个项目的列表.但是,如何防止旧代码的这种无声破坏呢?
-Wall -Wextra.() Foo b(20)对于其他构造函数,并且{}仅在我们真正意味着初始化列表时使用吗?这个声明很混乱:
char* q {new char[1024]{}}; // q[i] becomes 0 for all
Run Code Online (Sandbox Code Playgroud)
这是"指向char数组的char指针" 还是" 指针数组"?
我认为这new char[1024]{}是初始化一个char1024个元素的数组,每个元素的值为0.
所以这和:
char* q = [0,0,....] // until 1024
Run Code Online (Sandbox Code Playgroud)
正确?
我有以下代码:
#include <iostream>
#include <vector>
struct C {
int a;
C() : a(0) {}
C(int a) : a(a) {}
};
std::ostream &operator<<(std::ostream &os, const C &c) {
os << c.a;
return os;
}
using T = std::vector<C>;
int main() {
auto v = T({5});
for (const auto &a : v) {
std::cout << a << ", ";
}
std::cout << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我使用 g++,它会打印:
#include <iostream>
#include <vector>
struct C {
int a;
C() : a(0) {}
C(int …Run Code Online (Sandbox Code Playgroud) c++ vector initializer-list compiler-specific direct-initialization
c++ ×10
initializer-list ×10
c++11 ×6
c++14 ×1
constexpr ×1
constructor ×1
gcc ×1
iterator ×1
pointers ×1
shared-ptr ×1
vector ×1