右值成员的用例
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::optional
或 std::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_;
};
或者,更好的是,不要使用资源定位器。他们只是假装抽象的单身人士,但他们同样邪恶。
我发现了一段有趣的代码,我想知道它是不是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::optional
或 std::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_;
};
或者,更好的是,不要使用资源定位器。他们只是假装抽象的单身人士,但他们同样邪恶。