[C++] - 中的复制初始化(copy initialization)

过去在学习C++中类对象创建时,对constructor关注的很多,天真地认为了解了constructor,copy constructor,copy assignment就对类对象的创建理解了,今天遇到的一个看似不起眼的问题让我认识了还有copy initialization这么个东东,通过网上查阅揭开了copy initialization写神秘面纱,下面讲一下自己的一点理解。

首先看一下问题代码:

 

class String{
public:
	String() :str(""){ cout << "default constructor" << endl; }
	String(int n);

	String(const String &x) :str(x.str)
	{
		cout << "copy constructor" << endl;
	}
	String& operator=(const String &x)
	{
		str = x.str;
		cout << "operator =" << endl;
		return *this;
	}
	string getStr() const
	{
		return str;
	}
private:
	string str;
};

ostream& operator<<(ostream &o,const String &x)
{
	o << x.getStr();
	return o;
}

String::String(int n)
{
	stringstream ss;
	ss << n;
	ss >> str;
	ss.clear();
	ss.str("");
	cout << "String(int n)" << endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
	String s6 = 10;
	cout << s6 << endl;
	return 0;
}


运行结果如下图所示:

 

首先对于等式右边的10,能够理解使用了隐式转换调用了String(int n)创建了一个String对象,运行结果也确实是这样。但是为什么之后没有调用copy assignment等号操作符重载?原来关键是使用了copy initialization

其实,String s6 = 10;这不是一个赋值,这是一个初始化,准确的说是复制初始化(copy initialization)。

copy initializaiton: initializes an object from another object

copy initialization有以下几种形式:

 

T object = other;(1) 
 
T object = {other;(2)(until C++11)
 
f(other)(3) 
 
return other;(4) 
 
throw object;

catch (T object)

(5) 
 
T array[N] = {other};(6)

本文中的是第一种形式。它的实现过程准确的说是:

If T is a class type, and the cv-unqualified version of the type of other is not T or derived from T, or if T is non-class type, but the type of other is a class type, user-defined conversion sequences that can convert from the type of other to T (or to a type derived from T if T is a class type and a conversion function is available) are examined and the best one is selected through overload resolution. The result of the conversion, which is a prvalue temporary(until C++17)prvalue expression (since C++17) if a converting constructor was used, is then used to direct-initialize the object. The last step is usually optimized out and the result of the conversion is constructed directly in the memory allocated for the target object, but the appropriate constructor (move or copy) is required to be accessible even though it's not used. (until C++17)

也就是说,当other不是T类或T类子类的对象时,将会选择一个最佳的转换函数将other转换成T类。在本文中String(int n)就是上文中的converting constructor,而converting constructor是属于user-defined conversion sequences的一部分。因此本文中String(int n)将会被调用将10转变为String对象,转换的结果是一个prvalue temporary(类似右值的临时值),这个prvalue temporary然后将被用来直接初始化(direct initialize)T类对象(在本文中就是s6)。但是直接初始化(direct initialize)这步通常被优化了,即转换的结果直接在内存中construct并且分配给目标对象。在本文中,就是在栈上调用String(10)创建了一个String类的对象,然后将这个对象直接给s6,过程等价于执行了s6(10),所以才会出现运行结果中的只执行了String(int n),并没有执行copy assignment,也就是上文所说的even though it's not used

 

自己的简单理解,如有错误,欢迎指正

 

参考链接:

copy initialization: http://en.cppreference.com/w/cpp/language/copy_initialization

converting constructor:http://en.cppreference.com/w/cpp/language/converting_constructor

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值