简体   繁体   English

RVO是否与“新”一起使用?

[英]Does RVO work with “new”?

Does copy elision kick in in this situation? 在这种情况下复制省略会踢吗? In other words, do modern compilers with copy elision avoid to call any copy constructor here? 换句话说,具有复制省略功能的现代编译器是否可以避免在此处调用任何复制构造函数?

class BigObj{};

BigObj fun()
{
  BigObj b;
  return b;
}
int main()
{
  BigObj *pb = new BigObj(fun());
}

I aim to store an object in a pointer. 我旨在将对象存储在指针中。 The object is returned by a function. 该对象由函数返回。 I want to store it without copying it. 我想存储它而不复制它。

I can't use c++11 我不能使用c ++ 11

IMO it is not entirely clear what you aim to achieve. IMO尚不清楚您要实现的目标。 If dynamic allocation is what you want to use, then your function should simply: 如果要使用动态分配,则函数应该简单地:

BigObj * fun()
{
  return new BigObj;
}
int main()
{
  BigObj *pb = fun();
}

... and save yourself the trouble. ...并为您省去麻烦。

Contrary to the previous revision of the answer, it turned out that the compiler can omit a substantial amount of work as long as it is in a static context that can be thoroughly analyzed: 与以前的答案版本相反,事实证明,只要编译器可以在静态上下文中进行全面分析,便可以省略大量工作:

class C {
public:
    C() {qDebug() << "C created";}
    C(const C & o) { qDebug() << "C copied"; }
};

C foo() {
    C c;
    qDebug() << &c;
    return c;
}

...
    C c = C(foo()); // note that `C c = ` is also copy construction
    qDebug() << &c;

The output verifies that both instances have the same address, so even in the context of a local, the instance is actually not stored in the stack frame of foo . 输出验证两个实例具有相同的地址,因此即使在本地环境中,该实例实际上也没有存储在foo的堆栈帧中。

Changing to: 更改为:

C * cp = new C(foo());
qDebug() << cp;

to my surprise also output the same address, with both the return by value copy and the copy constructor omitted. 令我惊讶的是,它也输出相同的地址,同时省略了按值返回副本和复制构造函数。 c in foo is constructed directly in the memory chunk, allocated by new . foo c直接在由new分配的内存块中构造。

In conclusion the C++ compiler is pretty smart at analyzing and doing every possible optimization. 总之,C ++编译器在分析和进行所有可能的优化方面非常聪明。

Turning off optimizations in the first and second case respectively: 在第一种情况和第二种情况下分别关闭优化:

C created
0x28fd97
C copied
C copied
C copied
0x28fdeb

...

C created
0x28fd97
C copied
C copied
0x34fd00

RVO is among those things that the standard permits, but does not specifically require. RVO是标准允许但没有特别要求的内容之一。 That said, most modern compilers (at least, with appropriately optimisation settings enabled) will implement it. 也就是说,大多数现代编译器(至少启用了适当的优化设置)都将实现它。 If you want a guarantee, however, you will need to read your compiler documentation. 但是,如果需要保证,则需要阅读编译器文档。

Since the aim is to dynamically allocate an object anyway, I would simply change the example so the called function does dynamic allocation. 由于目标是始终动态分配对象,因此我将简单地更改示例,以便被调用函数进行动态分配。 Instead of (the OP's code); 代替(OP的代码);

BigObj fun()
{
    BigObj b;
     //   presumably the point of fun() is that some initialisation
     //     of b occurs here
    return b;
}
int main()
{
    BigObj *pb = new BigObj(fun());
}

I would simply use 我会简单地使用

BigObj *fun()
{
    BigObj *b = new BigObj;
     //   presumably the point of fun() is that some initialisation
     //     of *b occurs here
    return b;
}
int main()
{
    BigObj *pb = fun();
}

and eliminate the potential copying of a BigObj all together. 并消除了一起复制BigObj的可能。 The only thing that is being copied around is the value of a pointer. 唯一要复制的是指针的值。 The compiler therefore does not rely on presence of C++11 move constructors to optimise the above, since it avoids unnecessary creation and copying of objects, so this meets the OPs need to not use C++11. 因此,编译器不依赖C ++ 11 move构造函数的存在来优化上述内容,因为它避免了不必要的对象创建和复制,因此可以满足OP不需要使用C ++ 11的需求。

Obviously, in either case, it would be good practice to match the usage of operator new with a corresponding operator delete. 显然,在任何一种情况下,将new操作符的用法与相应的delete操作符进行匹配都是一种好习惯。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM