- 论坛徽章:
- 2
|
回复 #42 OwnWaterloo 的帖子
以前一些悬疑问题, 终于释怀了……
-------- -------- -------- --------
比如这里:
http://bbs3.chinaunix.net/thread-1621888-1-1.html
是emacsnw牛说中了, 其实是gcc3的一个bug。
-------- -------- -------- --------
还有这里:
http://bbs3.chinaunix.net/thread-1505460-1-1.html
用上面的标准来判断2个调用:
1. A v1 = A();
2. A v2 = A(2, 3);
都满足条件2, 所以被允许直接在v1和v2上构造, 被允许优化为如下形式:
A v1;
A v2(2, 3);
-------- -------- -------- --------
而一些库中出现的"计算式构造函数" —— 就是上面的极端例子 —— 也是有道理的。
-------- -------- -------- 返回值
string cat(char const* s1, char const* s2) {
return string(s1, s2); // 满足条件1 省略复制
// 直接在临时对象t上构造, string t(s1, s2);
}
-------- -------- 高效调用
string v = cat("hello ", "c++" ); // 满足条件2, 直接在v上构造临时对象t。 允许被优化为:
string v("hello ", "c++" );
总共1次计算式构造。
-------- -------- 低效调用
string v; // 默认构造
v = cat("hello ", "world" ); // 赋值
总共构造2次(计算式构造t, 默认构造v), 赋值1次。
-------- -------- -------- 传入参数 (死板设计)
如果设计为:
void cat(string& s, char const* s1, char const* s2) {
s = string(s1, s2); // 1次计算式构造, 1次赋值
}
调用:
string s;
cat(s, "hello ", "c++" );
总共构造2次(默认构造s, 计算构造t), 赋值1次。
-------- -------- -------- 传入参数
实际上, 那个极端的例子的传入参数版本不应该死板的调用计算式构造函数。
string应该有一个cat成员, 在已构造好的对象上操作。
void cat(string& s, char const* s1, char const* s2) {
s.cat(s1, s2);
}
调用:
string s;
cat(s, "hello ", "c++" );
总共默认构造s 1次。 cat一次。
而cat可能会分配新的buf, 再丢弃原有buf —— 实际上, 类似于如下设计:
void cat(string& s, char const* s1, char const* s2) {
string calculator(s1, s2);
swap(s, calculator);
}
-------- -------- -------- 总结
对可以实现计算式构造函数的类型, 直接返回值, 可以避免1次无用的默认构造 —— 构造, 然后马上丢弃。
-------- -------- -------- --------
上面是按C++03标准分析的, 不知道具体优化情况如何。
C++0x(不太关注……) 添加了move语意, 不知道两种设计又会怎样。
-------- -------- -------- --------
C++真复杂 -_- |
|