这是一种击败 elision 以保持 dtor 副作用的方法吗?
Is this a way to defeat elision to keep dtor side effects?
我想确保析构函数的副作用保留在作为 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
,或者其他什么)。 从代码可维护性的角度来看,它很容易并不意味着它是安全的。
相关文章:
- 复制构造函数的奇怪副作用
- 冲突的 CLANG"虚拟 dtor"和"已弃用的复制运算符"警告
- 程序只适用于包含(无副作用)cout声明
- 为什么评估一个表达可能会产生副作用
- 如果一个类继承了一个带有虚拟 dtor 的类,为什么要删除一个没有虚拟 dtor 的类是可以的
- strncmp 有副作用吗?
- 对象的 ctor 和 dtor 必须在同一线程上吗?
- 具有必要副作用的静态初始化被优化掉了
- 使用运营商New分配的数据结构是否有任何副作用
- 为什么在这个分解的 std::string dtor 中有一个锁定的 xadd 指令?
- 操作员的排序规则和副作用
- 安全地向DTOR抛出例外
- dtor中的这个unique_lock是否有任何目的
- 如果 LTO 中的代码依赖于其构造的副作用,是否允许 LTO 删除未使用的全局对象?
- 默认参数中的 c++ new 运算符及其副作用
- 使用 gcc 的 -fno-math-errno 可能有什么副作用?
- 在 DTor 之前删除的静态对象创建的线程?
- 必须将 std::thread 加入 std::vector<std::thread> 两次以避免从线程 dtor 终止
- 返回对象的攻击子具有副作用
- 这是一种击败 elision 以保持 dtor 副作用的方法吗?