我一直在阅读复制椭圆和返回值优化如何通过避免调用对象复制构造函数来提高速度。我理解这些机制是如何运作的,但我想知道这是否会导致程序不像人们期望的那样行事。
实质上,我的问题是;如果我们编写复制构造函数而不创建另一个对象副本的对象会发生什么?换句话说,如果
AClass original;
AClass copy ( original );
// copy == original -> false
比如说,我们有一个类似的类:
// AClass.hpp
struct AClass
{
static int copyCount;
int copyNumber;
AClass():copyNumber(0){}
AClass( AClass const& original ):copyNumber(++copyCount){} // I think this is the signature for the copy constructor
};
// AClass.cpp
int AClass::count ( 0 );
这显然是很糟糕的行为,我不会说我做这样的事情。然而,重点是;如果我们依赖副本的副作用怎么办?在此示例中,跟踪我们已制作的副本数量。我希望优化不应该影响程序的运行方式。但是,复制elision可能导致以下代码失败:
// Main.cpp
AClass MakeAClass()
{
return AClass();
}
int main()
{
AClass copy ( MakeAClass() );
if ( AClass::copyCount == 1 )
{
return 0;
}
else
{
return -1;
}
}
当我在没有优化的情况下构建调试模式时,这可能返回0,但是当我启用优化时突然失败,并且MakeAClass的返回直接放在副本上,跳过复制构造函数。
当编译器尝试这些优化来查找副作用时是否检查?当你要求复制时,期望代码执行复制是错误的吗?
答案 0 :(得分:1)
是。如果复制构造函数(或移动构造函数或析构函数)具有副作用,则复制省略可以更改代码的行为。
这就是重点。如果它无法改变行为,那么就没有理由在标准中提及它。不会改变行为的优化已经被as-if规则所涵盖。 (1.9 / 1)即:
本国际标准中的语义描述定义了一个 参数化非确定性抽象机。这个国际 标准对符合结构没有要求 实现。特别是,他们不需要复制或模仿 抽象机器的结构。相反,符合实现 需要模仿(仅)抽象的可观察行为 机器,如下所述。
标准中明确提到了复制省略,因为它可能违反了这一规则。