C++构造函数强制要求rvalue作为入参的优势是什么?
问题解答
你提到的两种构造函数写法各有适用场景,首先我们先分析显式右值引用入参的设计优势:
class Foo { public: explicit Foo(Another_class&& input); };
- 明确传递所有权语义:这种写法直接告诉调用者,构造
Foo时会转移input对象的所有权,不会产生Another_class的拷贝开销,非常适合Another_class是大内存占用、拷贝成本极高的类型(比如带堆内存的容器、文件句柄、网络连接对象等)的场景。 - 编译期强制调用规则:要求入参必须是右值,也就是调用者要么传入临时对象,要么主动对左值调用
std::move,从语法层面避免了无意识的高成本拷贝,也让所有权转移的逻辑对调用者完全透明,调用者可以明确知道传入的对象在构造完成后处于可析构、不可正常使用的状态。 - 编译和维护成本更低:没有模板推导逻辑,编译速度更快;如果调用方式不符合要求,编译器会直接给出简单直观的类型不匹配报错,不会出现模板推导的冗长错误栈;同时接口定义非常清晰,看头文件就能明确知道构造函数只接收
Another_class类型的参数,不会出现意料之外的类型兼容问题。
再对比你提到的万能引用写法:
class Foo { public: template<typename T> explicit Foo(T&& input); };
这种写法灵活性更高,支持完美转发任意类型的左值、右值参数,但也有明显的弊端:
- 模板会为每一种不同的输入参数类型生成独立的构造函数实例,会增加二进制文件体积,也会拖慢编译速度。
- 容易出现意料之外的匹配问题:如果没有加足够的类型约束,万能引用的重载优先级可能高于默认的拷贝/移动构造函数,比如传入
Foo类型的左值时,可能会优先匹配到这个模板构造函数,导致诡异的编译错误或者运行时异常。 - 接口语义不清晰:仅看头文件无法判断构造函数实际要接收的参数类型,需要阅读内部实现才能明确,对代码维护不友好。
两种写法没有绝对的好坏之分,如果你的Foo类明确仅接收Another_class类型的参数,且确定要转移参数所有权,显式右值引用的写法更安全也更易维护;如果需要兼容多种可转换类型的入参,或者要把参数完美转发给内部成员的构造函数,再考虑使用万能引用的实现。
内容的提问来源于stack exchange,提问作者WhatABeautifulWorld
相关产品推荐
相关产品推荐

