在 c++ 中初始化对象的不同方法

Different ways of initializing an object in c++

本文关键字:方法 对象 c++ 初始化      更新时间:2023-10-16

想象一下这个类:

class Entity {
public:
int x, y;

Entity() : x(0), y(0) { }
Entity(int x, int y) : x(x), y(y) { }
}

以下是使用我认为我知道的内容初始化类的多种方法:

Entity ent1;                //Uses the default constructor, so x=0 and y=0
Entity ent2();              //Uses the default constructor, so x=0 and y=0 (Not sure)
Entity ent3(1, 2);          //Made constructor, so x=1 and y=2
Entity ent4 = Entity();     //Default constructor, so x=0 and y=0
Entity ent5 = Entity(2, 3); //Made constructor, so x=2 and y=3

我知道可以在堆内存上创建一个对象,但这不是我目前正在寻找的。

我的问题是,这些初始化对象的方式之间有什么区别?

我不确定我应该在什么时候使用哪一个。

初始化的区别不仅在于它采用的形式,还在于 在正在初始化的实体类型中。在本例中,它是一个具有已定义默认构造函数的类类型对象,以及一个具有参数的构造函数。

Entity ent1;  

上面的语句是默认初始化,它导致调用类Entity的默认构造函数。

<小时 />
Entity ent2();

如果可能的话,编译器会将上述声明视为函数原型。Entity将返回函数ent2的类型,它不接受任何参数。它被称为最令人烦恼的解析(MVP)案例,它的存在导致了误导性的"聪明愚蠢规则"的出现:"永远不要使用括号"。


在语句中,ent3对象调用匹配参数列表的用户定义构造函数:

Entity ent3(1, 2);    // calls Entity(int x, int y)

MVP 可以罢工的另一种情况是这样的:

Entity ent3_1(int(a), int(b));  // It's not what it looks like.

上面的ent3_1不是变量。该语句声明一个具有两个 int 参数的函数。int(a)int a相同是C语言和声明语法的遗留问题,它忽略了"额外"括号。

<小时 />
Entity ent4 = Entity();

ent4ent2C++11之前的情况的正确版本。默认构造函数作为值初始化的一部分调用。它的形式允许避免歧义解决原则,使ent2ent3_1不正确。这里的等号不是作业,因为这里不会发生operator=呼叫。它是声明语法的一部分,用于标记初始化表达式。

<小时 />
Entity ent5 = Entity(2, 3);

ent5是 ent3 案例的一个版本。作为值初始化的一部分调用的用户定义构造函数。


您的问题标记为 C++11,C++11 允许统一的初始化语法:

Entity ent12{};     // This is a legal alternative of ent2 case
Entity ent13{1, 2}; // A call to constructor or member initialization
Entity ent13{ int(a), int(b) }; // Not a function anymore
Entity ent14 = {};              // Not an assignment
Entity ent15 = Entity{2, 3};    // Not an assignment either!

请注意,统一初始化语法有一个警告。 例如,这一行

std::vector<int> v(10); 

声明一个包含 10 个元素的向量。但是这个

std::vector<int> v{10};

声明一个向量,该向量由值为 10 的 int 类型的单个元素初始化。发生这种情况是因为std::vector有一个定义了以下签名的构造函数:

vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );

如果您不能在不触发 MVP 的情况下使用 (),也不能在不调用不需要的构造函数的情况下使用 {},则值初始化赋值语法允许解决此问题。

附录:必看CppCon 2018:尼古拉·乔苏蒂斯"C++初始化的噩梦">