在c ++ 11中将指针传递给临时?

And*_*iov 7 c++ temporary-objects c++11 c++14 c++17

我有一个现有的功能:

void foo(const Key* key = nullptr)
{
  // uses the key
}
Run Code Online (Sandbox Code Playgroud)

我想将它指向临时Key对象(即rvalue),如:

foo(&Key());
Run Code Online (Sandbox Code Playgroud)

这会导致编译错误,但是在c ++ 11/14中有一种方法可以做到这一点吗?我当然可以这样做:

Key key;
foo(&key);
Run Code Online (Sandbox Code Playgroud)

但我不需要对象Key,我只需要它在foo()和foo()中

或者我可以这样做:

foo(new Key());
Run Code Online (Sandbox Code Playgroud)

但是这个对象不会被删除.

Vit*_*meo 6

我不认为这是一个好主意,但如果你真的想要一个临时的而且无法改变foo,你可以将临时转换为const&:

int main()
{
    foo(&static_cast<const Key&>(Key{}));
}
Run Code Online (Sandbox Code Playgroud)

wandbox上的实例


或者,您可以在方便的函数后面"隐藏"对象的创建:

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);
}
Run Code Online (Sandbox Code Playgroud)

wandbox.org上的实例


另一种选择:提供foo一个引用的重载:

void foo(Key&& key)
{
    foo(&key);
}
Run Code Online (Sandbox Code Playgroud)

  • @AndreyRubliov临时将存在,直到表达式结束,这将在`foo`返回之后.它的地址对整个`foo`仍然有效.未定义的行为将是存储该指针并在临时不再存在后使用它. (4认同)
  • @DavidHaim:从字面上看,我回答中的第一句话是 *“我认为这不是一个好主意,但如果你真的想要一个临时变量并且无法更改 foo,你可以将临时变量转换为 const&amp;”*... (3认同)
  • @DavidHaim:我不同意 - 这没有回答问题。OP的问题很清楚,并且有我提供的答案。这是否是一个好主意并不重要。在答案中提及这一点显然是一个很好的做法。 (3认同)
  • 它会导致未定义的行为吗? (2认同)
  • @DavidHaim 我猜讨厌是主观的。但是没有任何歧义或正在玩的“记忆游戏”。我同意过载将是 OP 问题的更好解决方案,并且通过提出它可以改进这个答案。但是这篇文章确实回答了被问到的问题。 (2认同)

Yak*_*ont 6

这是一个实用函数。std::move它基本上是1的倒数:

template<class T>
T& as_lvalue( T&& t ) { return t; }
Run Code Online (Sandbox Code Playgroud)

如果使用错误,可能会导致悬空引用。

然后你的代码就变成:

foo(&as_lvalue(Key()));
Run Code Online (Sandbox Code Playgroud)

“无法获取临时地址”的目标是因为否则您可能会由于隐式临时创建等原因而获得极其意外的行为。

在这种情况下,我们明确地获取临时地址。

它并不比创建命名值、调用函数,然后立即丢弃命名值更危险。


1 std::move接受一个 l 或 r 值并返回对其的右值引用,表明消费者应将其视为临时值,其存在将很快被丢弃。 as_lvalue接受 l 或 r 值引用并返回对其的左值引用,表明使用者应将其视为非临时对象,其存在将持续存在。

它们都是有效的操作,但std::move更重要。(std::move可以称为as_rvalue真的)。我建议不要使用像unmove.

  • @mattnewport 一个函数通过指针接受一个可选的输出参数,如果它存在或不存在,它会做不同的事情,所以你想将它传入。或者它通过指针接受一个非可选的输出参数,你想忽略它。或者它通过引用执行相同的操作。或者您正在与一个遗留 API 进行对话,该 API 在 in 参数中采用非常量指针。另外,它适用于可选的内参数。所有这些事例都会随着时间的流逝而消失,就像雨中的泪水一样。 (3认同)

Nik*_* C. 5

只需自己控制丢弃变量的范围即可:

{
    Key key;
    foo(&key);
} // <-- 'key' is destroyed here
Run Code Online (Sandbox Code Playgroud)