C++ 什么时候应该使用_uforceinline而不是inline?

C++ 什么时候应该使用_uforceinline而不是inline?,c++,visual-studio,inline-functions,C++,Visual Studio,Inline Functions,Visual Studio包括对_forceinline的支持。Microsoft Visual Studio 2005文档说明: __forceinline关键字覆盖 成本/效益分析和评估 论程序员的判断 相反 这就提出了一个问题:编译器的成本/收益分析何时是错误的?我怎么知道这是错的 在什么情况下,假设我比我的编译器更了解这个问题?唯一可以确定的方法是测量有无性能。除非您编写的是高性能关键代码,否则这通常是不必要的。只有在分析数据告诉您的情况下,您才比编译器更清楚。有几种情况下,编译器无法明

Visual Studio包括对_forceinline的支持。Microsoft Visual Studio 2005文档说明:

__forceinline关键字覆盖 成本/效益分析和评估 论程序员的判断 相反

这就提出了一个问题:编译器的成本/收益分析何时是错误的?我怎么知道这是错的


在什么情况下,假设我比我的编译器更了解这个问题?

唯一可以确定的方法是测量有无性能。除非您编写的是高性能关键代码,否则这通常是不必要的。

只有在分析数据告诉您的情况下,您才比编译器更清楚。

有几种情况下,编译器无法明确确定内联函数是否合适或有益。内联可能涉及编译器不愿意做出的权衡,但您确实做到了(例如,代码膨胀)


一般来说,现代编译器实际上非常擅长做出这个决定。

编译器是基于静态代码分析做出决定的,而如果您按照don所说的进行分析,那么您将执行一个动态分析,这种分析可能会影响更深远。对特定代码段的调用次数通常在很大程度上取决于其使用的上下文,例如数据。分析一组典型的用例就可以做到这一点。就我个人而言,我通过在自动回归测试中启用评测来收集这些信息。除了强制内联,我还展开了循环,并根据这些数据执行了其他手动优化,效果很好。事后再做一次评测也是非常必要的,因为有时候你的最大努力实际上会导致性能下降。再一次,自动化让这件事变得不那么痛苦


根据我的经验,很多时候,调整算法比直接代码优化的效果要好得多。

我为资源有限的设备开发了9年左右的软件,而我唯一看到需要使用
\uu forceinline
的时候,相机驱动程序需要将像素数据从捕获缓冲区复制到设备屏幕。在那里,我们可以清楚地看到,一个特定函数调用的成本确实占用了覆盖图的性能。

我使用它的一个地方是许可证验证

防止易*破解的一个重要因素是验证在多个位置而不是仅在一个位置获得许可,并且您不希望这些位置是同一个函数调用



*)请不要在讨论中说什么都可以破解——我知道。此外,单凭这一点也没有多大帮助

内联指令在用于以下功能时将完全无用:

递归, 长的 由循环组成


如果您知道函数将在一个位置多次被调用以进行复杂的计算时,希望使用u forceinline

强制执行此决定,那么最好使用u forceinline。例如,可能需要多次调用动画的矩阵乘法,以便探查器开始注意到对该函数的调用。正如其他人所说,编译器无法真正了解这一点,尤其是在编译时代码的执行未知的动态情况下。

实际上,即使使用了u forceinline关键字。Visual C++有时会选择不内联代码。(源:生成的程序集源代码。)

始终查看生成的汇编代码,其中速度非常重要(例如需要在每个帧上运行紧密的内部循环)


有时使用#define而不是inline就可以了。(当然,通过使用#define,您会失去很多检查,所以只有在真正重要的时候和地方才使用它)

事实上,boost已经加载了它

比如说

 BOOST_CONTAINER_FORCEINLINE flat_tree&  operator=(BOOST_RV_REF(flat_tree) x)
    BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value ||
                        allocator_traits_type::is_always_equal::value) &&
                         boost::container::container_detail::is_nothrow_move_assignable<Compare>::value)
 {  m_data = boost::move(x.m_data); return *this;  }

 BOOST_CONTAINER_FORCEINLINE const value_compare &priv_value_comp() const
 { return static_cast<const value_compare &>(this->m_data); }

 BOOST_CONTAINER_FORCEINLINE value_compare &priv_value_comp()
 { return static_cast<value_compare &>(this->m_data); }

 BOOST_CONTAINER_FORCEINLINE const key_compare &priv_key_comp() const
 { return this->priv_value_comp().get_comp(); }

 BOOST_CONTAINER_FORCEINLINE key_compare &priv_key_comp()
 { return this->priv_value_comp().get_comp(); }

 public:
 // accessors:
 BOOST_CONTAINER_FORCEINLINE Compare key_comp() const
 { return this->m_data.get_comp(); }

 BOOST_CONTAINER_FORCEINLINE value_compare value_comp() const
 { return this->m_data; }

 BOOST_CONTAINER_FORCEINLINE allocator_type get_allocator() const
 { return this->m_data.m_vect.get_allocator(); }

 BOOST_CONTAINER_FORCEINLINE const stored_allocator_type &get_stored_allocator() const
 {  return this->m_data.m_vect.get_stored_allocator(); }

 BOOST_CONTAINER_FORCEINLINE stored_allocator_type &get_stored_allocator()
 {  return this->m_data.m_vect.get_stored_allocator(); }

 BOOST_CONTAINER_FORCEINLINE iterator begin()
 { return this->m_data.m_vect.begin(); }

 BOOST_CONTAINER_FORCEINLINE const_iterator begin() const
 { return this->cbegin(); }

 BOOST_CONTAINER_FORCEINLINE const_iterator cbegin() const
 { return this->m_data.m_vect.begin(); }
BOOST\u CONTAINER\u FORCEINLINE flat\u tree&operator=(BOOST\u RV\u REF(flat\u tree)x)
BOOST_NOEXCEPT_IF((分配器_traits_类型::在容器上传播_移动_分配::值||
分配器(类型::是否总是相等::值)&&
boost::container::container\u detail::is\u nothrow\u move\u assignable::value)
{m_data=boost::move(x.m_data);返回*this;}
BOOST\u CONTAINER\u FORCEINLINE const value\u compare&priv\u value\u comp()const
{返回static_cast(this->m_data);}
BOOST\u CONTAINER\u FORCEINLINE value\u compare&priv\u value\u comp()
{返回static_cast(this->m_data);}
BOOST\u CONTAINER\u FORCEINLINE const key\u compare&priv\u key\u comp()const
{返回此->priv_value_comp().get_comp();}
BOOST\u CONTAINER\u FORCEINLINE key\u compare&priv\u key\u comp()
{返回此->priv_value_comp().get_comp();}
公众:
//访问者:
BOOST\u CONTAINER\u FORCEINLINE比较键\u comp()常量
{返回此->m_数据。获取_comp();}
BOOST\u容器\u FORCEINLINE值\u比较值\u comp()常量
{返回此->m_数据;}
BOOST\u CONTAINER\u FORCEINLINE分配器\u type get\u allocator()常量
{返回此->m_data.m_vect.get_分配器();}
BOOST\u CONTAINER\u FORCEINLINE常量存储的\u分配器\u type&get\u存储的\u分配器()常量
{返回此->m_data.m_vect.get_storage_allocator();}
BOOST\u CONTAINER\u FORCEINLINE存储的\u分配器\u type&get\u存储的\u分配器()
{返回此->m_data.m_vect.get_storage_allocator();}
BOOST_CONTAINER_FORCEINLINE迭代器begin()
{返回此->m_data.m_vect.begin();}
BOOST\u CONTAINER\u FORCEINLINE常量\u迭代器begin()常量
{返回此->cbegin();}
BOOST\u CONTAINER\u FORCEINLINE常量\u迭代器cbegin()常量
{返回此->m_data.m_vect.begin();}
用于SIMD代码

SIMD代码通常使用常量/幻数。在正则函数中,every
const\uuuum128 c=\umm\usetr\ups(1,2,3,4)成为内存引用

使用
\uu forceinline
,编译器可以加载它一次并重用该值,除非y