如何用包装类模拟const引用以持有临时对象?
自定义可持有临时对象const引用的包装类
首先说明std::cref报错的原因:
标准库的std::cref故意删除了右值重载(绑定临时对象的版本),因为std::reference_wrapper的设计目标是传递已有对象的引用,而非持有临时对象——允许绑定临时对象很容易导致误用,进而产生悬空引用。
而const string& a = string("abc")能生效,是C++的核心规则:当const左值引用绑定到临时对象时,临时对象的生命周期会被延长至该引用的生命周期结束。
你可以自己实现一个符合需求的包装类,利用这个规则来持有临时对象的const引用:
#include <string> #include <iostream> #include <utility> // 用于std::move template<typename T> class const_ref_wrapper { public: // 绑定左值对象 explicit const_ref_wrapper(const T& ref) : m_ref(ref) {} // 绑定右值(临时对象),触发生命周期延长规则 explicit const_ref_wrapper(const T&& ref) : m_ref(ref) {} // 隐式转换为原类型的const引用 operator const T&() const { return m_ref; } // 提供箭头运算符访问成员 const T* operator->() const { return &m_ref; } // 直接获取引用 const T& get() const { return m_ref; } private: const T& m_ref; }; // 辅助函数,简化包装类的创建 template<typename T> const_ref_wrapper<T> make_const_ref(const T& val) { return const_ref_wrapper<T>(val); } template<typename T> const_ref_wrapper<T> make_const_ref(const T&& val) { return const_ref_wrapper<T>(std::move(val)); } // 测试代码 int main() { // 绑定临时字符串对象 const_ref_wrapper<std::string> temp_wrap = make_const_ref(std::string("hello")); std::cout << temp_wrap.get() << std::endl; // 正常输出"hello",临时对象未销毁 // 绑定左值对象 std::string left_val = "world"; const_ref_wrapper<std::string> left_wrap = make_const_ref(left_val); std::cout << left_wrap.get() << std::endl; // 正常输出"world" }
注意事项
- 这个包装类的生命周期必须和它绑定的临时对象严格绑定:如果拷贝包装类对象,拷贝后的实例会引用同一个临时对象,但临时对象的生命周期只会延长到第一个创建的包装类对象销毁,后续拷贝的对象会变成悬空引用。如果需要支持安全拷贝,得改用
std::shared_ptr持有临时对象(但这会变成值语义,不再是纯引用语义)。 - 仅在能保证包装类的生命周期不会超过临时对象的有效周期时使用该类,否则会出现未定义行为。
内容的提问来源于stack exchange,提问作者ritter
相关产品推荐
相关产品推荐

