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

C++20中如何使用ref qualifier兼顾代码安全与可用性?

问题与解决方案

场景代码

#include <string>

struct S
{
    std::string s_;

    std::string_view get() const &
    {
        return s_;
    }

    std::string_view get() const && = delete;
};

// 我无法修改这段代码
struct T
{
    T(std::string_view const sv);  // 用sv执行安全操作
};

// 我无法修改这段代码
void f(std::string_view const &);

void g()
{
    f(S{}.get());  // 应当通过编译
    T t(S{}.get());  // 应当通过编译
    std::string_view sv = S{}.get();  // 应当编译失败
}

需求

使用ref qualifier时,要同时满足:

  • 禁止std::string_view sv = S{}.get()这类不安全用法(临时对象销毁后string_view会悬空)
  • 让f(S{}.get())、T t(S{}.get())这类仅在临时对象生命周期内使用string_view的安全操作正常编译
  • 不能通过包装f来实现,避免冗余代码

可行方案:返回受限的string_view包装类

核心思路是给get()返回一个定制的包装类型,精准控制它能转换到哪些类型、在什么场景下转换,既能适配安全的传参场景,又能阻止危险的赋值操作。

实现代码

#include <string>

// 定制包装类,控制string_view的安全传递
class SafeStringView
{
    std::string_view sv_;
public:
    explicit SafeStringView(std::string_view sv) noexcept : sv_(sv) {}

    // 适配f的const&参数:允许隐式转成const string_view&
    operator std::string_view const&() const noexcept { return sv_; }

    // 适配T的传值构造:允许右值转成string_view值
    operator std::string_view() const && noexcept { return sv_; }

    // 禁止左值转成string_view值,阻止直接赋值给变量
    operator std::string_view() const & = delete;
};

struct S
{
    std::string s_;

    SafeStringView get() const & noexcept
    {
        return SafeStringView(s_);
    }

    // 临时对象可以调用get,但返回的包装类只能安全使用
    SafeStringView get() const && noexcept
    {
        return SafeStringView(s_);
    }
};

// 原有不可修改的代码保持原样
struct T
{
    T(std::string_view const sv);
};

void f(std::string_view const &);

void g()
{
    f(S{}.get());  // 编译通过:隐式转成const string_view&
    T t(S{}.get());  // 编译通过:右值转成string_view值
    std::string_view sv = S{}.get();  // 编译失败:左值转值类型被禁用
}

方案细节

  • 精准控制转换场景:
    当SafeStringView作为左值(比如赋值给变量)时,只能转换为std::string_view const&,但直接转成string_view值的重载被删除,所以危险的赋值操作直接编译报错。
    当作为右值(直接传参)时,允许转成string_view值,完美适配f的引用参数和T的传值构造函数。
  • 零侵入原有代码:不需要修改f和T的任何代码,包装类的隐式转换完全匹配它们的参数要求,不用写冗余的包装函数。
  • 保障生命周期安全:临时对象S{}的生命周期会延续到整个表达式结束,所以f(S{}.get())和T t(S{}.get())中的string_view不会悬空,操作完全安全。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 04:15:42