I've discovered an interesting piece of code and I wonder if it is UB or not? At least, according to cppreference it should not be. Is it a valid case for using an r-value reference?
The lifetime of a temporary object may be extended by binding to a const lvalue reference or to an rvalue reference...
Something similar was discussed in this post, but it does not fully address my case.
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: This won't work the way you want it to. It likely won't be UB though, as long as instance_
references something that lives long enough to support an operator=(...)
call from load(...)
.
References of any kind, whether rvalue or lvalue, cannot be rebound once initialized, and cannot be left uninitialized. Fundamentally what you're wanting here cannot work using references.
The static instance_
will have to have already been initialized to some value on program startup, which would make:
instance_ = std::move(instance);
assign to the object that instance_
originally references, meaning this uses the assignment operator operator=
for the ServiceLocator<T>
, rather than rebinding the reference.
Even if it could work, RValues can only extend lifetimes to the natural scope where its initialized (as if they are object-values), and can only extend the lifetime when initialized with a true temporary object (e.g. a PR-value, such as a T()
expression or the result of a function returning a by-value object).
So even if rebinding was possible, this extension would not apply since the parameters are not producing temporary expressions.
If you're wanting to create a locator of an object that is immovable/uncopyable, maybe consider either using std::optional
or std::unique_ptr
to allow for a null-state, and offer an emplace
-like function to construct it in-place. Such as:
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_;
};
Or, better yet, just don't use resource locators. They're just singletons pretending to be an abstraction, but they're just as evil.