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(...)
.
Explanation
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.
Possible Alternative
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.