这是一种击败 elision 以保持 dtor 副作用的方法吗?

Is this a way to defeat elision to keep dtor side effects?

本文关键字:dtor 副作用 方法 elision 一种      更新时间:2023-10-16

我想确保析构函数的副作用保留在作为 RVO 候选函数的函数中。我的目标是在入口和出口时对堆栈进行快照,并存在预期的堆栈变量。这段代码似乎适用于 C++11,而无需使用编译器特定的选项,但我不知道在早期版本中执行此操作的方法,而无需添加虚假的 Test 实例来创建多个返回路径。是否有一些技术,这是否始终适用于 c++11?

class Test {
public:
    int m_i;
    Test() { m_i = 0; cout << "def_ctor" << endl; }
    Test(const Test& arg) { this->m_i = arg.m_i; cout << "copy_ctor" << endl;}
    ~Test() { cout << "dtor needed for side effects" << endl; }
};
Test foo() {
    Test ret;
    return std::move(ret);
}
int main()
{
    Test x=foo();
}
std::move不是

魔法,它只是一个返回对其参数的引用的函数,所以你应该能够在任何版本的C++中做同样的事情

template<typename T>
  const T&
  defeat_rvo(const T& t)
  { return t; }
Test foo() {
    Test ret;
    return defeat_rvo(ret);
}

我认为你也可以更直接地做到这一点,只需返回一个引用:

Test foo() {
    Test ret;
    const Test& ref = ret;
    return ref;
}

复制 elision 规则说,当 return 语句中的表达式是"非易失性自动对象的名称"时,可以直接在返回值中构造本地对象,但这里的情况并非如此,因为它是对对象的引用,而不是对象本身的名称。我不太确定这种情况,但演员表应该有效:

Test foo() {
    Test ret;
    return static_cast<const Test&>(ret);
}

这绝对不是对象的名称,也不是对象的别名名称,而是强制转换表达式。

不要返回你不想被省略的对象;任何这样的变化在未来的维护或重构下都是脆弱的。

通常,对象应该在可能发生的情况下支持省略;这对移动或复制构造的内容以及析构函数的作用施加了语义限制。

违反这些语义限制很容易(template<class T> T copy_of(T const& t){return t;},然后return copy_of(whatever);,或static_cast,或者其他什么)。 从代码可维护性的角度来看,它很容易并不意味着它是安全的。