Reputation: 415
So I have a class that manages a resource. Similar to std::mutex
, it has acquire
and release
methods. To be a good RAII-style programmer, I want to implement the analog to std::unique_lock
, to prevent the resource from from being acquired forever. However, for semantic reasons, acquire
and release
are const
functions (trust me on this one).
So that means that my constructor for my RAII class has a signature of RAIIType( const T &)
. This problem is, is that an rvalue will bind to this as well. I was hoping to pick SO's brain on a way to disallow this from happening.
In coding terms:
class ResourceType
{
public:
void acquire() const{}
void release() const{}
};
template< class T >
class RAIIClass
{
public:
RAIIClass(const T & in_t) : t(in_t) { t.acquire(); }
~RAIIClass() { t.release(); }
private:
const T & t;
};
ResourceType foo() { return ResourceType(); }
int main()
{
ResourceType x1;
const ResourceType & x2(x1);
{
RAIIClass<ResourceType> x(x1); //Allowable
}
{
RAIIClass<ResourceType> x(x2); //Allowable
}
{
RAIIClass<ResourceType> x(foo()); //Currently allowable, would like to disallow.
}
}
Any ideas?
Upvotes: 3
Views: 304
Reputation: 42594
An alternative to forbidding the creation of managers for temporaries is to change the manager class to store the managed object internally when invoked with a temporary (Demo at Coliru):
template< class T >
class RAIIClass;
template <typename T>
RAIIClass<T> make_guard(T&&);
template< class T >
class RAIIClass
{
public:
~RAIIClass() { t.release(); }
private:
friend RAIIClass make_guard<>(T&&);
RAIIClass(T&& in_t) : t(std::forward<T>(in_t)) { t.acquire(); }
T t;
};
template <typename T>
RAIIClass<T> make_guard(T&& t) {
return {std::forward<T>(t)};
}
ResourceType foo() { return {}; }
int main()
{
ResourceType x1;
const ResourceType & x2(x1);
{
auto x = make_guard(x1); //Allowable
}
{
auto x = make_guard(x2); //Allowable
}
{
auto x = make_guard(foo()); //Allowable too.
}
}
Upvotes: 2
Reputation: 219588
Add this constructor:
RAIIClass(const T&&) = delete;
This will bind to either const or non-const rvalues, where as both const and non-const lvalues will prefer your existing constructor:
RAIIClass(const T & in_t) : t(in_t) { t.acquire(); }
Upvotes: 8