一行函数模板c+的内联性保证+; 在C++标准库中,有许多线性函数模板。例如,std::move本质上只是一个cast,一个实现可能是: template<typename _Tp> constexpr typename std::remove_reference<_Tp>::type&& move(_Tp&& __t) noexcept { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); } 模板 constexpr typename std::remove_reference::type&& 移动(&&t)不例外 {return static_cast(__t);}
我知道实际上,std::move不会生成任何机器代码,因为它只是一个强制转换。我的问题是:标准中是否有任何保证说,对于像std::move或std::forward这样的函数(只做强制转换),它们必须始终是内联的(因此不会生成机器代码)?换句话说,(学究式)编译器是否可以将它们视为普通函数(即,将参数放在堆栈上,并生成call和ret指令)?这不是标准,而是Scott Meyer的有效CPP。一行函数模板c+的内联性保证+; 在C++标准库中,有许多线性函数模板。例如,std::move本质上只是一个cast,一个实现可能是: template<typename _Tp> constexpr typename std::remove_reference<_Tp>::type&& move(_Tp&& __t) noexcept { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); } 模板 constexpr typename std::remove_reference::type&& 移动(&&t)不例外 {return static_cast(__t);},c++,C++,我知道实际上,std::move不会生成任何机器代码,因为它只是一个强制转换。我的问题是:标准中是否有任何保证说,对于像std::move或std::forward这样的函数(只做强制转换),它们必须始终是内联的(因此不会生成机器代码)?换句话说,(学究式)编译器是否可以将它们视为普通函数(即,将参数放在堆栈上,并生成call和ret指令)?这不是标准,而是Scott Meyer的有效CPP。 第30项:了解内联的细节。 编译器优化是非常重要的 通常设计用于缺少函数调用的代码扩展,因此 内联函数
第30项:了解内联的细节。 编译器优化是非常重要的 通常设计用于缺少函数调用的代码扩展,因此 内联函数时,可以启用编译器执行上下文- 函数体上的特定优化。大多数编译器 切勿对“概述”的函数调用执行此类优化。
…
在内存有限的机器上,过于热心 内联可能会导致程序对于可用程序来说太大 空间即使使用虚拟内存,内联引起的代码膨胀也会导致 为了增加分页,降低了指令缓存命中率,并且 伴随这些事件的绩效惩罚。
…
另一方面,如果内联函数体非常短,则代码 为函数体生成的代码可能小于生成的代码 用于函数调用。如果是这样的话,内联函数可能会 实际上会导致更小的目标代码和更高的指令缓存命中率 速度
…
请记住,内联是对编译器的请求,而不是命令。 …
模板实例化独立于内联。如果你在写一篇文章 模板,并且您相信从 模板应该内联,内联声明模板
…
但是,如果您正在为没有理由希望内联的函数编写模板,请避免将模板内联声明(显式或隐式)。内联 有成本,您不希望未经事先考虑就招致成本。
…
... 让我们完成观察,内联是一个请求 编译器可能会忽略这一点。大多数编译器拒绝内联函数 他们认为太复杂(例如,那些包含循环或是递归的), 除最简单的虚拟函数调用外,所有调用都不支持内联 所有这些加起来就是:给定的内联函数是否实际是 内联取决于您正在使用的构建环境-主要是 编译器。幸运的是,大多数编译器的诊断级别 如果未能内联函数,将导致警告 您已要求他们这样做。 有时编译器会为内联函数生成函数体 即使他们非常愿意内联函数。例如 如果程序采用内联函数的地址,编译器 通常必须为其生成一个概述的函数体
如果你能拿到这本书,读一读整本书,它会消除你的许多疑虑 这不是来自标准,而是来自Scott Meyer的有效CPP。
第30项:了解内联的细节。 编译器优化是非常重要的 通常设计用于缺少函数调用的代码扩展,因此 内联函数时,可以启用编译器执行上下文- 函数体上的特定优化。大多数编译器 切勿对“概述”的函数调用执行此类优化。
…
在内存有限的机器上,过于热心 内联可能会导致程序对于可用程序来说太大 空间即使使用虚拟内存,内联引起的代码膨胀也会导致 为了增加分页,降低了指令缓存命中率,并且 伴随这些事件的绩效惩罚。
…
另一方面,如果内联函数体非常短,则代码 为函数体生成的代码可能小于生成的代码 用于函数调用。如果是这样的话,内联函数可能会 实际上会导致更小的目标代码和更高的指令缓存命中率 速度
…
请记住,内联是对编译器的请求,而不是命令。 …
模板实例化独立于内联。如果你在写一篇文章 模板,并且您相信从 模板应该内联,内联声明模板
…
但是,如果您正在为没有理由希望内联的函数编写模板,请避免将模板内联声明(显式或隐式)。内联 有成本,您不希望未经事先考虑就招致成本。
…
... 让我们完成观察,内联是一个请求 编译器可能会忽略这一点。大多数编译器拒绝内联函数 他们认为太复杂(例如,那些包含循环或是递归的), 除最简单的虚拟函数调用外,所有调用都不支持内联 所有这些加起来就是:给定的内联函数是否实际是 内联取决于您正在使用的构建环境-主要是 编译器。幸运的是,大多数编译器的诊断级别 如果未能内联函数,将导致警告 您已要求他们这样做。 有时编译器会为内联函数生成函数体 即使他们是完美的wil
#include <utility>
struct Foo {
int i;
Foo(Foo &&other) :i(other.i) {};
};
Foo with_move(Foo f) {
return std::move(f);
}
Foo::Foo(Foo&&):
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
mov QWORD PTR [rbp-16], rsi
mov rax, QWORD PTR [rbp-16]
mov edx, DWORD PTR [rax]
mov rax, QWORD PTR [rbp-8]
mov DWORD PTR [rax], edx
nop
pop rbp
ret
with_move(Foo):
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
mov QWORD PTR [rbp-16], rsi
mov rax, QWORD PTR [rbp-16]
mov rdi, rax
call std::remove_reference<Foo&>::type&& std::move<Foo&>(Foo&)
mov rdx, rax
mov rax, QWORD PTR [rbp-8]
mov rsi, rdx
mov rdi, rax
call Foo::Foo(Foo&&)
mov rax, QWORD PTR [rbp-8]
leave
ret
std::remove_reference<Foo&>::type&& std::move<Foo&>(Foo&):
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
mov rax, QWORD PTR [rbp-8]
pop rbp
ret
with_move(Foo):
mov rax, rdi
mov edx, DWORD PTR [rsi]
mov DWORD PTR [rdi], edx
ret