C++显式调用构造函数初始化对象有用到拷贝构造函数么?

作者:大漠刀客
链接:https://www.nowcoder.com/discuss/29421
来源:牛客网

下面代码中的HasPtr hp4 = HasPtr(1,str);
这里有用到拷贝构造函数,拷贝构造函数中的语句“调用拷贝构造函数”
并没有输出。
但是将拷贝构造函数中的const去掉变成HasPtr(  HasPtr& hp)又报错了,
拷贝构造函数中的第一个参数必须是引用类型,但未必是const吧?
而且从正确使用时的输出看,这里拷贝构造函数HasPtr( const HasPtr& hp)并没有调用啊

 #include <iostream>
#include <memory>

using std::string;
using std::cout;
using std::endl;

class HasPtr{
public:
    HasPtr() = default;
    HasPtr( int i1,string &str ){
        i = i1;
        ps = &str;
    }
    HasPtr( const HasPtr& hp){
        i = hp.i;
        ps = new string( *hp.ps );
        cout<<"调用拷贝构造函数"<<endl;
    }
    int i;
    string *ps;
};
int main(  ){
    string str = "hello";
    HasPtr hp4 = HasPtr(1,str);
    cout<<hp4.i<<" "<<hp4.ps<<endl;
    return 0;
}

拷贝构造被调用的三个条件
1.对象拷贝(A a;B b(a))
2.对象作为参数传值
3.对象作为函数返回值被赋值给左值

对于HasPtr hp4 = HasPtr(1,str);来说,一般来讲应该是表达式右端先生成一个临时对象,然后调用拷贝构造函数初始化hp4.
但是这其中的临时对象其实是多余的,所以编译器就将这种形式的表达式优化成了HasPtr hp4(1, str);,也就是跳过了临时对象的
创建过程,节省了调用一次拷贝构造函数的消耗。

至于拷贝构造函数中使用非const引用导致报错,这是因为HasPtr hp4 = HasPtr(1,str);中HasPtr(1,str)是右值,非const的左值
无法绑定到右值上,可以使用右值引用或者const引用(直接按值传递也可以,但是在此例中不行,会导致无穷递归)。