右值成员的用例

A use-case for r-value members

我发现了一段有趣的代码,我想知道它是不是UB?至少,根据 cppreference 不应该。使用 r 值参考是否有效?

The lifetime of a temporary object may be extended by binding to a const lvalue reference or to an rvalue reference...

this post 中讨论了类似的内容,但没有完全解决我的问题。

template <typename T>
class ResourceLocator {
public:
    static void load(ResourceLocator<T>&& instance) {
        instance_ = std::move(instance);
    }

protected:
    static ResourceLocator<T>&& instance_;
    // static ResourceLocator<T>& instance_; // does not extend lifetime
    // static const ResourceLocator<T>&& instance_; // const is too limiting

TL;DR: 这不会按您希望的方式工作。不过,它可能不会是 UB,只要 instance_ 引用的内容足够长以支持来自 load(...).

operator=(...) 调用

说明

任何类型的引用,无论是右值还是左值,一旦初始化就不能重新绑定,也不能保持未初始化状态。从根本上说,您在这里想要的 无法使用引用

静态 instance_ 必须在程序启动时已经初始化为某个值,这将使:

instance_ = std::move(instance);

分配给 instance_ 最初引用的对象,这意味着这对 ServiceLocator<T> 使用赋值运算符 operator=,而不是重新绑定引用。

即使它可以工作,RValues 也只能将生命周期延长到其初始化的自然范围(就像它们是对象值一样),并且只能在以下情况下延长生命周期用真正的临时对象初始化(例如PR值,如T()表达式或返回按值对象的函数的结果)。

因此,即使可以重新绑定,此扩展也不会适用,因为参数不会生成临时表达式。

可能的选择

如果您想创建 immovable/uncopyable 对象的定位器,可以考虑使用 std::optionalstd::unique_ptr 以允许空状态,并提供一个类似于 emplace 的函数来就地构建它。如:

template <typename T>
class ResourceLocator {
public:
    template <typename...Args>
    static void emplace(Args&&...args) {
        instance_.emplace(std::forward<Args>(args)...);
    }
private:
    static std::optional<ResourceLocator<T>> instance_;
};

或者,更好的是,不要使用资源定位器。他们只是假装抽象的单身人士,但他们同样邪恶。