C++ 在使用“初始化”时()和{}总是等价的;新的;?

C++ 在使用“初始化”时()和{}总是等价的;新的;?,c++,c++11,constructor,initialization,new-operator,C++,C++11,Constructor,Initialization,New Operator,有一个帖子是关于如何使用新功能的。但是这个呢: 如果“测试”是一个普通类,那么以下两者之间是否有任何区别: Test* test = new Test(); // and Test* test = new Test{}; 此外,假设Test2有一个类型为Value的参数的构造函数,它是否总是等同于写入: Value v; Test2 *test2 = new Test(v); // and Test2 *test2 = new Test{v}; 在涉及std::initializer\u l

有一个帖子是关于如何使用新功能的。但是这个呢:

如果“测试”是一个普通类,那么以下两者之间是否有任何区别:

Test* test = new Test();
// and
Test* test = new Test{};
此外,假设
Test2
有一个类型为
Value
的参数的构造函数,它是否总是等同于写入:

Value v;
Test2 *test2 = new Test(v);
// and
Test2 *test2 = new Test{v};

在涉及
std::initializer\u list
的上下文中可能存在差异,例如:

案例1-
()
{}

#include <initializer_list>
#include <iostream>
using namespace std;

struct Test2 {
    Test2(initializer_list<int> l) {}
};

int main() {
    Test2* test3 = new Test2(); // compile error: no default ctor
    Test2* test4 = new Test2{}; // calls initializer_list ctor
}
正如Meyers和其他人所说,使用STL时也存在巨大差异:

    using Vec = std::vector<int>;
    Vec* v1 = new Vec(10); // vector of size 10 holding 10 zeroes
    Vec* v2 = new Vec{10}; // vector of size 1 holding int 10
在这种情况下,还有一个众所周知的区别

void f() {
    Test test{};
    Test test2();
}
其中,
test
是类型为
test
的默认初始化对象,
test2
是函数声明。

新的初始值设定项可以采用以下形式:

新初始值设定项:
表达式列表opt

大括号初始化列表

以及:

[C++11:5.3.4/15]:
创建类型为
T
的对象的新表达式将该对象初始化如下:

  • 如果省略了新的初始值设定项,则对象默认已初始化(8.5);如果未执行初始化,则对象的值不确定
  • 否则,新的初始值设定项将根据8.5的初始化规则进行解释,以进行直接初始化
以及:

[C++11:8.5/15]:
表单中发生的初始化

T x(a);
T x{a};
new
表达式(5.3.4)、
static\u cast
表达式(5.2.9)、函数表示法类型转换(5.2.3)以及基和成员初始值设定项(12.6.2)中,也被称为直接初始化

以及:

[C++11:8.5/16]:
初始值设定项的语义如下所示。[……]

  • 如果初始值设定项是一个(非圆括号)带括号的初始列表,则对象或引用将被列表初始化(8.5.4)
  • [……]
  • 如果初始值设定项为
    ()
    ,则对象的值已初始化
  • [……]
  • 如果初始化是直接初始化,或者是复制初始化,其中源类型的cv非限定版本与目标类的类或派生类相同,则会考虑构造函数。列举了适用的施工人员(13.3.1.3),以及 通过过载分辨率(13.3)选择一个。调用如此选择的构造函数来初始化对象,并将初始值设定项表达式或表达式列表作为其参数。如果没有应用构造函数,或者重载解析不明确,则初始化是错误的
  • [……]
因此,您可以看到,在这种情况下(以及其他一些情况下),这两种情况都被定义为直接初始化,但进一步的规则意味着,根据您是使用
()
还是
{}
以及初始化器是否为空,可能会发生不同的情况


考虑到列表初始化的规则,我不会在这里重复,如果
T
没有构造函数采用
std::initializer\u list

的话,这两个初始值设定项的效果基本相同。一般的答案是否定的。使用带括号的init list作为初始值设定项将首先尝试解析为采用
std::initializer\u list
的构造函数。举个例子:

#include <iostream>
#include <vector>
int main() {
  auto p = new std::vector<int>{1};
  auto q = new std::vector<int>(1);
  std::cout << p->at(0) << '\n';
  std::cout << q->at(0) << '\n';
}
#包括
#包括
int main(){
autop=newstd::vector{1};
自动q=新标准::向量(1);

std::cout at(0)这一点已在对该问题的回答中说明,该问题是“后续问题”该死的,你是对的,如果初始化器是一个有支撑的init列表,直接初始化本身就延迟列表初始化。Scott Meyers的C++中有一个专门用于它的项目。是的,但是这个例子被迈尔斯真正忽略了——当没有()或{}时我认为他们在第一种情况下是不同的too@sp2danny列表初始化的语义非常复杂,不同版本的C++也有不同的表述。不管怎样,我决定把答案保留到现在,因为它是日常编程中最相关的部分,人们应该熟悉它。如果
T
不是一个集合,那么让它更准确的答案也是受欢迎的。
T x(a);
T x{a};
#include <iostream>
#include <vector>
int main() {
  auto p = new std::vector<int>{1};
  auto q = new std::vector<int>(1);
  std::cout << p->at(0) << '\n';
  std::cout << q->at(0) << '\n';
}