C++类型擦除场景下模板类拷贝构造函数未触发问题求助
问题根因
你遇到的现象是C++万能引用的类型推导规则+引用折叠共同作用的结果,具体推导过程如下:
- 执行
Object obj2(a2)时,a2是左值,匹配Object的模板构造函数的万能引用参数T&& obj:- 按照万能引用的推导规则,传入左值时模板参数
T会被推导为左值引用类型A& - 结合引用折叠规则,
T&&即A& &&会折叠为A&,最终构造函数的形参就是A&类型,完美匹配传入的左值a2
- 按照万能引用的推导规则,传入左值时模板参数
- 构造
Model实例时用的模板参数是推导出来的T = A&,因此实例化的是Model<A&>类:- 该类的成员变量
T obj_实际是A&类型,也就是左值引用,而非A类型的实例 Model构造函数的形参T&& obj同样会折叠为A&,初始化obj_(std::forward<T>(obj))的本质是把形参引用绑定到成员引用,完全不需要调用A的拷贝构造函数
- 该类的成员变量
- 所以你运行时看到三个地址完全一致,都是栈上
a2本身的地址,也没有拷贝构造的日志输出,完全符合代码逻辑。
修复方案
如果你的预期是Model内存储擦除类型的独立实例,而非引用外部变量,需要在实例化Model时去掉T的引用、cv等限定符,用std::decay处理模板参数即可:
把Object构造函数的初始化列表修改为:
object_(std::make_shared<Model<typename std::decay<T>::type>>(std::forward<T>(obj)))
(gcc4.8还不支持C++14的std::decay_t别名,所以用typename std::decay<T>::type写法即可)
修改后再运行测试用例2,T被decay处理为纯类型A,Model<A>的成员是A类型实例,初始化时就会触发你预期的A的拷贝构造函数。
内容的提问来源于stack exchange,提问作者Navy
相关产品推荐
相关产品推荐

