I have an existing function:
void foo(const Key* key = nullptr)
{
// uses the key
}
I want to pass it pointer to temporary Key object (i.e. rvalue) like:
foo(&Key());
This causes compilation error, but is there a way in c++ 11/14 how I can do this? Of course I could do:
Key key;
foo(&key);
But I don't need object Key, I only need it inside foo() and foo()
Or I could do:
foo(new Key());
But then the object will not be deleted.
I don't think this is a good idea, but if you really really want a temporary and cannot change foo
, you can cast the temporary to a const&
:
int main()
{
foo(&static_cast<const Key&>(Key{}));
}
live example on wandbox
Alternatively, you could "hide" the creation of the object behind a convenient function:
template <typename T, typename F, typename... Ts>
void invoke_with_temporary(F&& f, Ts&&... xs)
{
T obj{std::forward<Ts>(xs)...};
f(&obj);
}
int main()
{
invoke_with_temporary<Key>(&foo);
}
live example on wandbox.org
Another alternative: provide an overload of foo
that takes a reference:
void foo(Key&& key)
{
foo(&key);
}
if what you concern is variable scope (as you mention in comment) you can use
{Key key;foo(&key);}
Just control the scope of the throw-away variable yourself:
{
Key key;
foo(&key);
} // <-- 'key' is destroyed here
This is a utilty function. It is basically the inverse of std::move
1:
template<class T>
T& as_lvalue( T&& t ) { return t; }
if used wrong it can lead to dangling references.
Your code then becomes:
foo(&as_lvalue(Key()));
the goal of "cannot take an address of a temporary" is because you can otherwise get extremely unexpected behaviour due to things like implicit temporary creation.
In this case, we are explicitly taking the address of a temporary.
It is no more dangerous than creating a named value, calling the function, and then discarding the named value immediately.
1std::move
takes an l or r value and returns a rvalue reference to it, indicating that consumer should treat it as a temporary whose existence will be shortly discarded. as_lvalue
takes an l or r value reference and returns an lvalue reference to it, indicating that the consumer should treat it as a non-temporary whose existence will persist.
They are both valid operations, but std::move
is more crucial. (std::move
could be called as_rvalue
really). I'd advise against clever names like unmove
.
The only reason to take a pointer rather than a reference is if the pointer can be null. And if that's the case, then your foo
function will look something like this:
void foo(const Key *key)
{
if(key)
//Do stuff with `key`
else
//Alternate code
}
Given that, what you want is a second overload, one that refactors all of the "do stuff with key" into its own function that takes a reference. So do that:
void foo(const Key &key)
{
//Do stuff with `key`
}
void foo(const Key *key)
{
if(key)
foo(*key);
else
//Alternate code.
}
If you have common code that gets executed in both cases, refactor that out into its own function too.
Yes, it's possible that "do stuff with key" is complicated and is split up into several lines. But that suggests a very strange design here.
You could also refactor it the other way:
void foo(const Key &key) {foo(&key);}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With