Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass pointer to temporary in c++ 11?

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.

like image 244
Andrey Rubliov Avatar asked Nov 23 '17 14:11

Andrey Rubliov


5 Answers

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);
}
like image 187
Vittorio Romeo Avatar answered Nov 01 '22 09:11

Vittorio Romeo


if what you concern is variable scope (as you mention in comment) you can use

{Key key;foo(&key);}

like image 26
apple apple Avatar answered Sep 28 '22 03:09

apple apple


Just control the scope of the throw-away variable yourself:

{
    Key key;
    foo(&key);
} // <-- 'key' is destroyed here
like image 4
Nikos C. Avatar answered Nov 01 '22 11:11

Nikos C.


This is a utilty function. It is basically the inverse of std::move1:

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.

like image 4
Yakk - Adam Nevraumont Avatar answered Nov 01 '22 10:11

Yakk - Adam Nevraumont


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);}
like image 3
Nicol Bolas Avatar answered Nov 01 '22 11:11

Nicol Bolas