You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建具备类似引用语义的C++类型包装器?

如何实现将值语义类型包装为表现如引用的对象?

需求描述

需要一个包装类Wrap<T>,让值语义类型T表现出引用语义:多个容器中的Wrap<T>对象共享同一个底层值,修改其中一个会同步影响所有其他对象,示例代码如下:

int a = 20;

std::list<Wrap<int>> l1;
l1.push_back(a);

std::list<Wrap<int>> l2;
l2.push_back(a);

l2.front() = 10;

cout << l1.front() << endl; // 期望输出10

同时有以下疑问:

  • 考虑过std::shared_ptr,但不确定指针语义是否符合需求
  • 想知道标准库中有无现成替代方案
  • 发现std::reference_wrapper是将引用当作值类型使用,与需求相反,该如何解决?

解决方案

核心思路

你的需求本质是让多个包装对象共享同一个底层值实例,并自动管理值的生命周期。std::shared_ptr其实是最贴合需求的标准库工具,它提供了共享所有权的指针语义,配合简单的运算符重载就能让它表现得像值类型。

1. 自定义包装类(推荐)

基于std::shared_ptr封装一个Wrap类,重载必要的运算符,让使用方式完全贴近值类型:

#include <iostream>
#include <list>
#include <memory>

template<typename T>
class Wrap {
private:
    std::shared_ptr<T> m_ptr;
public:
    // 构造:接受值类型,创建共享实例
    explicit Wrap(const T& val) : m_ptr(std::make_shared<T>(val)) {}
    Wrap(T&& val) : m_ptr(std::make_shared<T>(std::move(val))) {}
    
    // 拷贝/赋值默认即可,shared_ptr自动处理引用计数
    Wrap(const Wrap&) = default;
    Wrap& operator=(const Wrap&) = default;
    
    // 重载赋值运算符:修改底层值
    T& operator=(const T& val) {
        *m_ptr = val;
        return *m_ptr;
    }
    T& operator=(T&& val) {
        *m_ptr = std::move(val);
        return *m_ptr;
    }
    
    // 隐式转换为T&,支持直接读取和修改
    operator T&() { return *m_ptr; }
    operator const T&() const { return *m_ptr; }
};

int main() {
    int a = 20;

    std::list<Wrap<int>> l1;
    l1.push_back(a);

    std::list<Wrap<int>> l2;
    l2.push_back(a);

    l2.front() = 10;

    std::cout << l1.front() << std::endl; // 输出10
    return 0;
}

这个包装类的优势:

  • 完全满足你给出的示例效果,使用方式和普通值类型一致
  • 自动管理底层值的生命周期,即使原始的a被销毁,容器中的Wrap对象仍能安全访问共享值
  • 支持移动语义,性能高效

2. 直接使用std::shared_ptr

如果不想自定义类,直接用std::shared_ptr也能实现需求,只是使用时需要显式解引用:

#include <iostream>
#include <list>
#include <memory>

int main() {
    int a = 20;

    std::list<std::shared_ptr<int>> l1;
    auto shared_val = std::make_shared<int>(a);
    l1.push_back(shared_val);

    std::list<std::shared_ptr<int>> l2;
    l2.push_back(shared_val); // 共享同一个实例

    *l2.front() = 10;

    std::cout << *l1.front() << std::endl; // 输出10
    return 0;
}

注意:必须让多个容器的shared_ptr指向同一个实例,不能各自调用std::make_shared<int>(a)(否则会创建独立的实例,无法共享修改)。

关于std::reference_wrapper

你说的没错,std::reference_wrapper确实和需求相反:它的作用是将已有对象的引用包装成可拷贝的对象,让容器能存储引用类型(容器不能直接存裸引用)。但它依赖于原始对象的生命周期,一旦原始对象(比如示例中的a)被销毁,容器中的reference_wrapper就会变成悬空引用,存在安全隐患。而且它无法创建新的共享实例,只能绑定已有对象,不符合你需求中“包装值语义类型”的核心诉求。

标准库的替代方案

标准库中没有专门为“值语义转引用语义”设计的包装器,因为std::shared_ptr已经提供了核心的共享所有权机制,自定义一层包装就能满足语法上的需求。


内容的提问来源于stack exchange,提问作者user2138149

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 07:45:31