C++ 中的常量和编译器优化

发布于 2024-07-08 04:31:38 字数 211 浏览 11 评论 0原文

我已经阅读了 C++ 中关于 const 正确性的所有建议,并且它很重要(部分),因为它可以帮助编译器优化代码。 我从未见过关于编译器如何使用这些信息来优化代码的很好的解释,即使是好书也没有继续解释幕后发生的事情。

例如,编译器如何优化声明为 const 的方法与不是但应该声明为 const 的方法。 当引入可变变量时会发生什么? 它们会影响 const 方法的这些优化吗?

I've read all the advice on const-correctness in C++ and that it is important (in part) because it helps the compiler to optimize your code. What I've never seen is a good explanation on how the compiler uses this information to optimize the code, not even the good books go on explaining what happens behind the curtains.

For example, how does the compiler optimize a method that is declared const vs one that isn't but should be. What happens when you introduce mutable variables? Do they affect these optimizations of const methods?

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

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

发布评论

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

评论(12

命比纸薄 2024-07-15 04:31:39

const 是直接优化的最明显的一点是向函数传递参数。 确保函数不会修改数据通常很重要,因此函数签名的唯一真正选择是:

void f(Type dont_modify); // or
void f(Type const& dont_modify);

当然,这里真正的魔力是传递引用而不是创建对象的(昂贵的)副本。 但如果引用没有标记为 const,这会削弱该函数的语义并产生负面影响(例如使错误跟踪变得更加困难)。 因此,const 在这里启用了优化。

/编辑:实际上,一个好的编译器可以分析函数的控制流,确定它不会修改参数并本身进行优化(传递引用而不是副本)。 这里的const只是对编译器的帮助。 然而,由于 C++ 有一些相当复杂的语义,并且这种控制流分析对于大型函数来说可能非常昂贵,因此我们可能不应该依赖编译器来实现这一点。 有人有任何数据支持我/证明我错了吗?

/EDIT2:是的,一旦自定义复制构造函数发挥作用,它就会变得更加棘手,因为不幸的是,不允许编译器在这种情况下省略调用它们。

The most obvious point where const is a direct optimization is in passing arguments to a function. It's often important to ensure that the function doesn't modify the data so the only real choices for the function signature are these:

void f(Type dont_modify); // or
void f(Type const& dont_modify);

Of course, the real magic here is passing a reference rather than creating an (expensive) copy of the object. But if the reference weren't marked as const, this would weaken the semantics of this function and have negative effects (such as making error-tracking harder). Therefore, const enables an optimization here.

/EDIT: actually, a good compiler can analyze the control flow of the function, determine that it doesn't modify the argument and make the optimization (passing a reference rather than a copy) itself. const here is merely a help for the compiler. However, since C++ has some pretty complicated semantics and such control flow analysis can be very expensive for big functions, we probably shouldn't rely on compilers for this. Does anybody have any data to back me up / prove me wrong?

/EDIT2: and yes, as soon as custom copy constructors come into play, it gets even trickier because compilers unfortunately aren't allowed to omit calling them in this situation.

楠木可依 2024-07-15 04:31:39

此代码

class Test
{
public:
  Test (int value) : m_value (value)
  {
  }

  void SetValue (int value) const
  {
    const_cast <Test&>(*this).MySetValue (value);
  }

  int Value () const
  {
    return m_value;
  }

private:
  void MySetValue (int value)
  {
    m_value = value;
  }

  int
    m_value;
};

void modify (const Test &test, int value) 
{
  test.SetValue (value);
}

void main ()
{
  const Test
    test (100);

  cout << test.Value () << endl;
  modify (test, 50);
  cout << test.Value () << endl;
}

输出:

100
50

这意味着 const 声明的对象已在 const 成员函数中更改。 C++ 语言中 const_cast(以及 mutable 关键字)的存在意味着 const 关键字无法帮助编译器生成优化的代码。 正如我在之前的文章中指出的,它甚至可以产生意想不到的结果。

作为基本规则:

const !=优化

事实上,这是一个合法的 C++ 修饰符:

volatile const

This code,

class Test
{
public:
  Test (int value) : m_value (value)
  {
  }

  void SetValue (int value) const
  {
    const_cast <Test&>(*this).MySetValue (value);
  }

  int Value () const
  {
    return m_value;
  }

private:
  void MySetValue (int value)
  {
    m_value = value;
  }

  int
    m_value;
};

void modify (const Test &test, int value) 
{
  test.SetValue (value);
}

void main ()
{
  const Test
    test (100);

  cout << test.Value () << endl;
  modify (test, 50);
  cout << test.Value () << endl;
}

outputs:

100
50

which means the const declared object has been altered in a const member function. The presence of const_cast (and the mutable keyword) in the C++ language means that the const keyword can't aide the compiler in generating optimised code. And as I pointed out in my previous posts, it can even produce unexpected results.

As a general rule:

const != optimisation

In fact, this is a legal C++ modifier:

volatile const
╭⌒浅淡时光〆 2024-07-15 04:31:39

const 帮助编译器优化主要是因为它使您可以编写可优化的代码。 除非你输入const_cast

const helps compilers optimize mainly because it makes you write optimizable code. Unless you throw in const_cast.

晨与橙与城 2024-07-15 04:31:38

我认为const关键字主要是为了程序语义的编译检查而引入的,而不是为了优化。

Herb Sutter 在 GotW #81 文章 中很好地解释了为什么编译器不能通过 const 引用传递参数或声明 const 返回值时优化任何内容。 原因是编译器无法确保引用的对象不会更改,即使声明为 const :可以使用 const_cast,或者某些其他代码可以在同一对象上拥有非常量引用。

然而,引用 Herb Sutter 的文章:

[只有]一种情况说
“const”确实可以意味着一些东西,并且
那就是当对象被设为常量时
它们被定义的点。 在那里面
在这种情况下,编译器通常可以
成功地把这样的“真正的常量”
对象写入只读内存[...]。

本文还有很多内容,因此我鼓励您阅读它:之后您将对持续优化有更好的理解。

I think that the const keyword was primarily introduced for compilation checking of the program semantic, not for optimization.

Herb Sutter, in the GotW #81 article, explains very well why the compiler can't optimize anything when passing parameters by const reference, or when declaring const return value. The reason is that the compiler has no way to be sure that the object referenced won't be changed, even if declared const : one could use a const_cast, or some other code can have a non-const reference on the same object.

However, quoting Herb Sutter's article :

There is [only] one case where saying
"const" can really mean something, and
that is when objects are made const at
the point they are defined. In that
case, the compiler can often
successfully put such "really const"
objects into read-only memory[...].

There is a lot more in this article, so I encourage you reading it: you'll have a better understanding of constant optimization after that.

沦落红尘 2024-07-15 04:31:38

让我们忽略方法,只看 const 对象; 编译器在这里有更多的优化机会。 如果一个对象被声明为 const,则 (ISO/IEC 14882:2003 7.1.5.1(4)):

除了声明的任何类成员
可变(7.1.1)可以修改,任何
尝试修改 const 对象
在其生命周期内(3.8)导致
未定义的行为。

让我们忽略可能具有可变成员的对象 - 编译器可以自由地假设该对象不会被修改,因此它可以产生显着的优化。 这些优化可以包括以下内容:

  • 将对象的值直接合并到机器指令操作码中
  • 完全消除永远无法到达的代码,因为 const 对象用于编译时已知的条件表达式
  • 如果 const 对象正在控制,则展开循环循环的迭代次数

请注意,此内容仅适用于实际对象为 const 的情况 - 它不适用于通过 const 指针或引用访问的对象,因为这些访问路径可能会导致非 const 对象(甚至更好) - 定义为通过 const 指针/引用更改对象,只要实际对象是非常量,并且您放弃了对象访问路径的常量性)。

实际上,我认为没有编译器可以对所有类型的 const 对象执行任何重要的优化。 但对于原始类型(整数、字符等)的对象,我认为编译器在优化方面可能非常积极
这些物品的使用。

Let's disregard methods and look only at const objects; the compiler has much more opportunity for optimization here. If an object is declared const, then (ISO/IEC 14882:2003 7.1.5.1(4)):

Except that any class member declared
mutable (7.1.1) can be modified, any
attempt to modify a const object
during its lifetime (3.8) results in
undefined behavior.

Lets disregard objects that may have mutable members - the compiler is free to assume that the object will not be modified, therefore it can produce significant optimizations. These optimizations can include things like:

  • incorporating the object's value directly into the machines instruction opcodes
  • complete elimination of code that can never be reached because the const object is used in a conditional expression that is known at compile time
  • loop unrolling if the const object is controlling the number of iterations of a loop

Note that this stuff applies only if the actual object is const - it does not apply to objects that are accessed through const pointers or references because those access paths can lead to objects that are not const (it's even well-defined to change objects though const pointers/references as long as the actual object is non-const and you cast away the constness of the access path to the object).

In practice, I don't think there are compilers out there that perform any significant optimizations for all kinds of const objects. but for objects that are primitive types (ints, chars, etc.) I think that compilers can be quite aggressive in optimizing
the use of those items.

药祭#氼 2024-07-15 04:31:38

handwaving 开始

从本质上讲,数据越早被修复,编译器就越能在数据的实际分配中移动,确保管道不会停止

end handwaving

handwaving begins

Essentially, the earlier the data is fixed, the more the compiler can move around the actual assignment of the data, ensuring that the pipeline doesn't stall out

end handwaving

别把无礼当个性 2024-07-15 04:31:38

嗯。 常量正确性更多的是一种样式/错误检查而不是优化。 全面优化的编译器将跟踪变量的使用情况,并可以检测变量何时是有效的 const。

除此之外,编译器不能依赖你告诉它真相——你可能会丢弃它不知道的库函数中的 const 。

所以,是的,常量正确性是一个值得追求的目标,但它不会告诉编译器任何它自己无法弄清楚的事情,假设有一个良好的优化编译器。

Meh. Const-correctness is more of a style / error-checking thing than an optimisation. A full-on optimising compiler will follow variable usage and can detect when a variable is effectively const or not.

Added to that, the compiler cannot rely on you telling it the truth - you could be casting away the const inside a library function it doesn't know about.

So yes, const-correctness is a worthy thing to aim for, but it doesn't tell the compiler anything it won't figure out for itself, assuming a good optimising compiler.

小梨窩很甜 2024-07-15 04:31:38

它不会优化声明为 const 的函数。

它可以优化调用声明为const的函数的函数。

void someType::somefunc();

void MyFunc()
{
    someType A(4);   // 
    Fling(A.m_val);
    A.someFunc();
    Flong(A.m_val);
}

这里要调用 Fling,值 A.m_val 必须加载到 CPU 寄存器中。 如果 someFunc() 不是 const,则必须在调用 Flong() 之前重新加载该值。 如果 someFunc 是 const,那么我们可以使用仍在寄存器中的值调用 Flong。

It does not optimize the function that is declared const.

It can optimize functions that call the function that is declared const.

void someType::somefunc();

void MyFunc()
{
    someType A(4);   // 
    Fling(A.m_val);
    A.someFunc();
    Flong(A.m_val);
}

Here to call Fling, the valud A.m_val had to be loaded into a CPU register. If someFunc() is not const, the value would have to be reloaded before calling Flong(). If someFunc is const, then we can call Flong with the value that's still in the register.

画中仙 2024-07-15 04:31:38

方法设置为const的主要原因是为了const的正确性,而不是为了方法本身可能的编译优化。

如果变量是const,那么它们(理论上)可以被优化掉。 但编译器只能看到范围。 毕竟编译器必须允许在其他地方使用 const_cast 修改它们。

The main reason for having methods as const is for const correctness, not for possible compilation optimization of the method itself.

If variables are const they can (in theory) be optimized away. But only is the scope can be seen by the compiler. After all the compiler must allow for them to be modified with a const_cast elsewhere.

蘑菇王子 2024-07-15 04:31:38

这些都是正确的答案,但答案和问题似乎假定了一件事:编译器优化实际上很重要。

只有一种代码对编译器优化很重要,即在

  • 紧密内部循环的代码中,
  • 在您编译的代码中,而不是第 3 方库,
  • 不包含函数或方法调用(甚至是隐藏的调用),
  • 程序计数器花费了相当大一部分时间的地方

如果其他 99% 的代码被优化到 N 级,那不会有什么不同,因为它只在程序计数器实际花费时间的代码中重要(您可以通过抽样找到)。

Those are all true answers, but the answers and the question seem to presume one thing: that compiler optimization actually matters.

There is only one kind of code where compiler optimization matters, that is in code that is

  • a tight inner loop,
  • in code that you compile, as opposed to a 3rd-party library,
  • not containing function or method calls (even hidden ones),
  • where the program counter spends a noticeable fraction of its time

If the other 99% of the code is optimized to the Nth degree, it won't make a hoot of difference, because it only matters in code where the program counter actually spends time (which you can find by sampling).

你穿错了嫁妆 2024-07-15 04:31:38

如果优化器实际上将大量库存放入 const 声明中,我会感到惊讶。 有很多代码最终会抛弃常量性,这将是一个非常鲁莽的优化器,它依赖于程序员声明来假设状态何时可能改变。

I would be surprised if the optimizer actually puts much stock into a const declaration. There is a lot of code that will end up casting const-ness away, it would be a very reckless optimizer that relied on the programmer declaration to assume when the state may change.

天涯离梦残月幽梦 2024-07-15 04:31:38

const-正确性作为文档也很有用。 如果函数或参数被列为 const,我不需要担心代码中的值发生变化(除非团队中的其他人非常顽皮)。 不过,如果它没有内置到库中,我不确定它是否真的值得。

const-correctness is also useful as documentation. If a function or parameter is listed as const, I don't need to worry about the value changing out from under my code (unless somebody else on the team is being very naughty). I'm not sure it would be actually worth it if it wasn't built into the library, though.

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