编译器优化

发布于 2024-12-02 11:30:21 字数 1314 浏览 5 评论 0原文

所以我有一个问题要问你。 :) 你能告诉我以下代码应该产生的输出吗?

#include <iostream>
struct Optimized
{
    Optimized() { std::cout << "ctor" << std::endl; }
    ~Optimized() { std::cout << "dtor" << std::endl; }
    Optimized(const Optimized& copy) { std::cout << "copy ctor" << std::endl; }
    Optimized(Optimized&& move) { std::cout << "move ctor" << std::endl; }
    const Optimized& operator=(const Optimized& rhs) { std::cout << "assignment operator" << std::endl; return *this; }
    Optimized& operator=(Optimized&& lhs) { std::cout << "move assignment operator" << std::endl; return *this; }
};

Optimized TestFunction()
{
    Optimized a;
    Optimized b = a;
    return b;
}

int main(int argc, char* argv[])
{
    Optimized test = TestFunction();
    return 0;
}

我的第一反应是:

  1. ctor
  2. copy ctor
  3. move ctor
  4. dtor
  5. dtor
  6. dtor

,这是真的,但仅当编译器优化关闭时。当优化打开时,输出完全不同。打开优化后,输出为:

  1. ctor
  2. copy ctor
  3. dtor
  4. dtor

通过编译器优化,测试变量是返回变量。

我的问题是,什么条件会导致无法以这种方式优化?

我一直被教导,返回一个导致额外复制构造函数的结构/类可以通过作为引用传递来更好地进行优化,但编译器正在为我做这件事。那么 return 结构仍然被认为是不好的形式吗?

So I have a question for you. :)
Can you tell me the output the following code should produce?

#include <iostream>
struct Optimized
{
    Optimized() { std::cout << "ctor" << std::endl; }
    ~Optimized() { std::cout << "dtor" << std::endl; }
    Optimized(const Optimized& copy) { std::cout << "copy ctor" << std::endl; }
    Optimized(Optimized&& move) { std::cout << "move ctor" << std::endl; }
    const Optimized& operator=(const Optimized& rhs) { std::cout << "assignment operator" << std::endl; return *this; }
    Optimized& operator=(Optimized&& lhs) { std::cout << "move assignment operator" << std::endl; return *this; }
};

Optimized TestFunction()
{
    Optimized a;
    Optimized b = a;
    return b;
}

int main(int argc, char* argv[])
{
    Optimized test = TestFunction();
    return 0;
}

My first response would be:

  1. ctor
  2. copy ctor
  3. move ctor
  4. dtor
  5. dtor
  6. dtor

and it IS true, but only if compiler optimization is turned off. When optimization is turned ON then the output is entirely different. With optimization turned on, the output is:

  1. ctor
  2. copy ctor
  3. dtor
  4. dtor

With compiler optimization, the test variable is the return variable.

My question is, what conditions would cause this to not be optimized this way?

I have always been taught that returning a struct/class which results in extra copy constructors could better be optimized by being passed in as a reference but the compiler is doing that for me. So is return a structure still considered bad form?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

我最亲爱的 2024-12-09 11:30:21

这称为“复制省略”,是一种特殊处理,而不是复制/移动。

标准特别允许优化,只要可以复制/移动(即,该方法已声明且可访问)。

在这种情况下,编译器中的实现通常称为“返回值优化”。有两种变体:

  • RVO:当您返回临时值时 (return "aa" + someString;)
  • NRVO:N 表示命名,当您返回一个具有名称的对象

两者都是由主要编译器实现的,但后者可能仅在更高的优化级别上启动,因为它更难以检测。

因此,要回答您有关返回结构的问题:我会推荐它。考虑一下:

// Bad
Foo foo;
bar(foo);

-- foo can be modified here


// Good
Foo const foo = bar();

后者不仅更清晰,而且还允许 const 强制执行!

This is known as Copy Elision and is a special handling instead of copying/moving.

The optimization is specifically allowed by the Standard, as long as it would be possible to copy/move (ie, the method is declared and accessible).

The implementation in a compiler is generally referred to, in this case, as Return Value Optimization. There are two variations:

  • RVO: when you return a temporary (return "aa" + someString;)
  • NRVO: N for Named, when you return an object that has a name

Both are implemented by major compilers, but the latter may kick in only at higher optimization levels as it is more difficult to detect.

Therefore, to answer your question about returning structs: I would recommend it. Consider:

// Bad
Foo foo;
bar(foo);

-- foo can be modified here


// Good
Foo const foo = bar();

The latter is not only clearer, it also allows const enforcement!

等风来 2024-12-09 11:30:21

两种输出都是允许的。 C++03 语言标准在第 12.8/15 条中规定:

当满足某些条件时,允许实现省略类对象的复制构造,
即使对象的复制构造函数和/或析构函数有副作用。在这种情况下,实施
将省略的复制操作的源和目标视为简单的两种不同的引用方式
同一个对象,并且该对象的销毁发生在两个对象被破坏的较晚的时间
如果没有优化,就会被破坏。111) 这种复制操作的省略在
以下情况(可以组合起来消除多个副本):

  • 在具有类返回类型的函数的 return 语句中,当表达式是
    具有与函数返回类型相同的 cv-unqualified 类型的非易失性自动对象,副本
    通过直接将自动对象构造到函数的返回值中可以省略操作
  • 当尚未绑定到引用(12.2)的临时类对象被复制到类时
    具有相同 cv-unqualified 类型的对象,可以通过构造临时对象来省略复制操作
    对象直接进入省略复制的目标

Both outputs are permissible. The C++03 language standard says, in clause 12.8/15:

When certain criteria are met, an implementation is allowed to omit the copy construction of a class object,
even if the copy constructor and/or destructor for the object have side effects. In such cases, the implementation
treats the source and target of the omitted copy operation as simply two different ways of referring to
the same object, and the destruction of that object occurs at the later of the times when the two objects
would have been destroyed without the optimization.111) This elision of copy operations is permitted in the
following circumstances (which may be combined to eliminate multiple copies):

  • in a return statement in a function with a class return type, when the expression is the name of a
    non-volatile automatic object with the same cv-unqualified type as the function return type, the copy
    operation can be omitted by constructing the automatic object directly into the function’s return value
  • when a temporary class object that has not been bound to a reference (12.2) would be copied to a class
    object with the same cv-unqualified type, the copy operation can be omitted by constructing the temporary
    object directly into the target of the omitted copy
等往事风中吹 2024-12-09 11:30:21

此代码将产生的输出是不可预测的,因为语言规范明确允许选择性消除(省略)类对象的“不必要的”临时副本,即使它们的复制构造函数有副作用。

这种情况是否会发生可能取决于多种因素,包括编译器优化设置。

在我看来,将上述复制省略称为“优化”并不完全正确(尽管在这里使用这个术语的愿望是完全可以理解的,并且它被广泛用于此目的)。我想说,术语优化应该保留在编译器偏离抽象C++机器同时保留可观察的行为的情况程序的行为。换句话说,真正的优化意味着违反语言规范的抽象要求。由于在这种情况下没有违规(标准明确允许复制省略),因此没有真正的“优化”。我们在这里观察到的只是 C++ 语言在其抽象级别上的工作方式。根本不需要涉及“优化”的概念。

The output this code will produce is unpredictable, since the language specification explicitly allows optional elimination (elision) of "unnecessary" temporary copies of class objects even if their copy constructors have side effects.

Whether this will happen or not might depend on may factors, including the compiler optimization settings.

In my opinion calling the above copy elision an "optimization" is not entirely correct (although the desire to use this term here is perfectly understandable and it is widely used for this purpose). I'd say that the term optimization should be reserved to situations when the compiler deviates from the behavior of the abstract C++ machine while preserving the observable behavior of the program. In other words, true optimization implies violation of the abstract requirements of the language specification. Since in this case there's no violation (the copy elision is explicitly allowed by the standard), there's no real "optimization". What we observe here is just how the C++ language works at its abstract level. No need to involve the concept of "optimization" at all.

作死小能手 2024-12-09 11:30:21

即使按值传回,编译器也可以使用返回值优化来优化额外的副本,请参阅; http://en.wikipedia.org/wiki/Return_value_optimization

Even when passing back by value the compiler can optimise the extra copy away using Return Value Optimisation see; http://en.wikipedia.org/wiki/Return_value_optimization

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文