官术网_书友最值得收藏!

Additions to compile-time facilities

With C++11, constexpr was added as a statement to the compiler that a variable, function, and so on, can be evaluated at compile time and optimized, reducing the complexity of the code at runtime and improving performance overall. In some cases, the compiler was smart enough to extend constexpr statements to other components, including branch statements, for example:

#include <iostream>

constexpr const auto val = true;

int main(void)
{
if (val) {
std::cout << "Hello World\n";
}
}

In this example, we have created a constexpr variable, and we only output Hello World to stdout if constexpr is true. Since, in this example, it's always true, the compiler will remove the branch from the code entirely, as shown here:

push %rbp
mov %rsp,%rbp
lea 0x100(%rip),%rsi
lea 0x200814(%rip),%rdi
callq 6c0 <...cout...>
mov $0x0,%eax
pop %rbp
retq

As you can see, the code loads a couple of registers and calls std::cout without checking whether val is true, since the compiler completely removed the code from the resulting binary. The issue with C++11 was that the author could assume that this type of optimization was taking place, when in fact it might not be. 

To prevent this type of error, C++17 adds a constexpr if statement, which tells the compiler to specifically optimize the branch at compile time. If the compiler cannot optimize the if statement, an explicit compile-time error will occur, telling the user that optimization could not be done, providing the user with an opportunity to fix the issue (instead of assuming the optimization was taking place when in fact it might not be), for example:

#include <iostream>

int main(void)
{
if constexpr (constexpr const auto i = 42; i > 0) {
std::cout << "Hello World\n";
}
}

// > g++ scratchpad.cpp; ./a.out
// Hello World

In the preceding example, we have a more complicated if statement that leverages both a compile-time constexpr optimization as well as an if statement initializer. The resulting binary is as follows:

push %rbp
mov %rsp,%rbp
sub $0x10,%rsp
movl $0x2a,-0x4(%rbp)
lea 0x104(%rip),%rsi
lea 0x200809(%rip),%rdi
callq 6c0 <...cout...>
mov $0x0,%eax
leaveq
retq

As you can see, the branch has been removed from the resulting binary, and more specifically, if the expression was not a constant, the compiler would have thrown an error stating that this code could not be compiled as stated.

It should be noted that this result is not the same binary as previously as one might expect. It would appear that GCC 7.3 has some additional improvements to make in its optimization engine, as the constexpr i variable that was defined and initialized inside the binary was not removed (as stack space was allocated for i in this code when it didn't need to be). 

Another compile-time change was a different version of the static_assert compile-time function. In C++11, the following was added:

#include <iostream>

int main(void)
{
static_assert(42 == 42, "the answer");
}

// > g++ scratchpad.cpp; ./a.out
//

The goal of the static_assert function is to ensure that certain compile-time assumptions are true. This is especially helpful when programming a system to do things such as making sure a structure is a specific size in bytes, or that a certain code path is taken, depending on the system you're compiling for. The problem with this assert was that it required the addition of a description that would be output during compile time, which likely just describes the assertion in English without providing any additional information. In C++17, another version of this assert was added, which removed the need for the description, as follows:

#include <iostream>

int main(void)
{
static_assert(42 == 42);
}

// > g++ scratchpad.cpp; ./a.out
//
主站蜘蛛池模板: 桐乡市| 永川市| 夹江县| 龙陵县| 横山县| 兴安县| 黄山市| 榆中县| 高州市| 开化县| 景泰县| 镇远县| 泗洪县| 正镶白旗| 曲水县| 新巴尔虎右旗| 齐河县| 遵化市| 邛崃市| 乳山市| 稻城县| 沁源县| 溧水县| 弋阳县| 岳池县| 台湾省| 玉环县| 九台市| 固镇县| 太湖县| 县级市| 油尖旺区| 彭水| 北辰区| 高邮市| 南城县| 富裕县| 桃园市| 蓝田县| 蒙山县| 额尔古纳市|