gpt4 book ai didi

c++ - 绑定(bind)到引用时临时对象生命周期扩展异常的基本原理是什么?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:27:33 25 4
gpt4 key购买 nike

在 C++11 标准的 12.2 中:

The temporary to which the reference is bound or the temporary that isthe complete object of a subobject to which the reference is boundpersists for the lifetime of the reference except:

  1. A temporary boundto a reference member in a constructor’s ctor-initializer (12.6.2)persists until the constructor exits.

  2. A temporary bound to areference parameter in a function call (5.2.2) persists until thecompletion of the full-expression containing the call.

  3. The lifetimeof a temporary bound to the returned value in a function returnstatement (6.6.3) is not extended; the temporary is destroyed at theend of the full-expression in the return statement.

  4. A temporarybound to a reference in a new-initializer (5.3.4) persists until thecompletion of the full-expression containing the new-initializer.

标准中有最后一个案例的例子:

struct S {
int mi;
const std::pair<int,int>& mp;
};
S a { 1,{2,3} }; // No problem.
S* p = new S{ 1, {2,3} }; // Creates dangling reference

对我来说,2。和 3. 有道理且容易达成一致。但是绑定(bind) 1 的原因是什么?和 4.?这个例子在我看来很邪恶。

最佳答案

与 C 和 C++ 中的许多事情一样,我认为这归结为可以合理(有效)实现的内容。

临时对象通常分配在堆栈上,调用它们的构造函数和析构函数的代码被发送到函数本身。因此,如果我们将您的第一个示例扩展为编译器实际执行的操作,它将看起来像:

  struct S {
int mi;
const std::pair<int,int>& mp;
};

// Case 1:
std::pair<int,int> tmp{ 2, 3 };
S a { 1, tmp };

编译器可以很容易地延长 tmp 临时文件的生命周期,使“S”保持有效,因为我们知道“S”会在函数结束前被销毁。

但这在“新 S”情况下不起作用:

  struct S {
int mi;
const std::pair<int,int>& mp;
};

// Case 2:
std::pair<int,int> tmp{ 2, 3 };
// Whoops, this heap object will outlive the stack-allocated
// temporary!
S* p = new S{ 1, tmp };

为了避免悬垂引用,我们需要在堆上而不是堆栈上分配临时对象,例如:

   // Case 2a -- compiler tries to be clever?
// Note that the compiler won't actually do this.
std::pair<int,int> tmp = new std::pair<int,int>{ 2, 3 };
S* p = new S{ 1, tmp };

但是相应的delete p 需要释放这个堆内存!这与引用的行为完全相反,并且会破坏任何使用正常引用语义的东西:

  // No way to implement this that satisfies case 2a but doesn't
// break normal reference semantics.
delete p;

所以你的问题的答案是:规则是以这种方式定义的,因为它是给定 C++ 围绕堆栈、堆和对象生命周期的语义的唯一实用解决方案。

警告:@Potatoswatter 在下面指出,这似乎并没有在 C++ 编译器中一致地实现,因此目前充其量是不可移植的。请参阅他的示例,了解 Clang 如何不执行标准似乎在此处强制执行的操作。他还说情况“可能比那更可怕”——我不知道这到底是什么意思,但在实践中,C++ 中的这种情况似乎存在一些不确定性。

关于c++ - 绑定(bind)到引用时临时对象生命周期扩展异常的基本原理是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21920311/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com