首页 新闻 会员 周边

C++直接初始化和复制初始化的疑问

0
悬赏园豆:20 [待解决问题]

C++primer上说:
“直接初始化和复制初始化。复制初始化使用=符号,而直接初始化将初始化式放在圆括号中。
当用于类类型对象时,初始化的复制形式和直接形式有所不同:直接初始化直接调用与实参匹配的构造函数,复制初始化总是调用复制构造函数。复制初始化首先使用指定构造函数创建一个临时对象(7.3.2节),然后使用复制构造函数将那个临时对象复制到正在创建的对象:
string   null_book   =   "9-999-99999-9 ";//copy-initialization
string   dots(10, '. ');//direct-initialization
string   empty_copy   =   string();//copy-initialization
string   empty_direct;//direct-initialization
对于类类型对象,只有指定单个实参或显式创建一个临时对象用于复制时,才使用复制初始化。
创建dots时,调用参数为一个数量和一个字符的string构造函数并直接初始化dots的成员。创建null_book时,编译器首先调用接受一个C风格字符串形参的string构造函数,创建一个临时对象,然后,编译器使用string复制构造函数将null_book初始化为那个临时对象的副本。
empty_copy和empty_direct的初始化都调用默认构造函数。对前者初始化时,默认构造函数创建一个临时对象,然后复制构造函数用该对象初始化empty_copy。对后者初始化时,直接运行empty_direct的默认构造函数”
请看下面的例子:

#include <iostream>
#include <cstdlib>
 
using namespace std;
 
class A
{
public:
    A(){cout << "constructor called!" << endl;}
    A(int i) : x(i){cout << i << " constructor called!" << endl;}
    A(const A &a){cout << x << " copy constructor called!" << endl;}
    ~A(){cout << x << " destructor called" << endl;}
private:
    //A(const A &a){cout << "copy constuctor called!" << endl;}
    int x;
};
 
A get_A()
{
    A a(5);
    return a;
}
 
int main()
{
    A a = 1;system("pause");       // 1
 
    A b = get_A();system("pause"); // 2
 
    b = a;system("pause");         // 3
 
    A c = A(2);system("pause");    // 4
 
    b = 3;system("pause");         // 5
 
    A d = b;system("pause");       // 6
    return 0;
}

在CB中编译运行结果:

按照B.Lippman的说法, 显示的结果应该不是这个样子的, 但是编译器有优化, 跳过了有些不必要的复制构造函数的调用, 现在说说我的理解, 不知道对不对, 希望大家都说说自己的看法, 谢谢!
第1句, 生成了临时对象, 但是编译器优化,跳过了复制构造函数。
第2句, 在VS中的运行结果是这样的:

当从函数返回该类型的对象时, 调用复制构造函数, VS中是正常应该出现的结果, 但是CB中却没有, 我猜是g++优化的比VS好吧。
第3句, 调用的是编译器默认生成的赋值操作符(=), 大概应该是这样的:

void operator = (const A &a)
{
   x = a.x;
}

第4句, 和第一句差不多, 我猜第1句A a = 1等效于A a = A(1).
第5句, 先生成临时对象, 然后再调用编译器生成的赋值操作符(=)。
第6句, 从结果显示只调用了复制构造函数, 到底有没有临时对象生成, 请大家说说自己的看法。
另外, 我把get_A函数换成了如下形式:

A get_A()
{
   return A(5);
}

在VS中的显示结果:

我很疑问, 复制构造函数怎么没有被调用?难道又是编译器的优化? 请大家给我解释解释, 谢谢!

c++
huster2014的主页 huster2014 | 初学一级 | 园豆:182
提问于:2012-11-17 20:37
< >
分享
所有回答(1)
0

我想是应该会优化的,

A get_A()
{
    A a(5);
    return a;
}
这种写法中,因为a在栈上,函数结束时,需要析构,所以必须copy construct成另外一个对象返回。
A get_A()
{
   return A(5);
}
这种写法中,编译器应该就可以大胆地直接把构造出来的对象返回了。所以真的可能是一种优化。

Google了一下,还真有,http://en.wikipedia.org/wiki/Return_value_optimization

楼主真是个细心人啊。


__熊_ | 园豆:238 (菜鸟二级) | 2012-11-18 21:14
谢谢你的回复!但是, 
A get_A() { A a(
5); return a; }

这种写法在CB中, 从结果上看没有调用复制构造函数, 这是为什么呢?g++优化能力很犀利?

支持(0) 反对(0) huster2014 | 园豆:182 (初学一级) | 2012-11-18 21:38

@wj@wust: 这个真不清楚了,标准里没有规定编译器应该怎么返回,只要返回正确的值就行,

也许可以反汇编一下,看看生成的二进制代码。

支持(0) 反对(0) __熊_ | 园豆:238 (菜鸟二级) | 2012-11-19 19:11
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册