是std::映射表初始化优化

Is std::map table initialization optimized?

本文关键字:初始化 优化 映射 std      更新时间:2023-10-16

考虑到问题末尾的示例,是否每次调用函数GetName()时都会创建映射对象
还是创建将被优化并创建为某个查找表?

#include <iostream>
#include <sstream>
#include <map>
#include <string>
#include <boost/assign/list_of.hpp>
enum abc
{
    A = 1,
    B,
    C
};
std::string GetName( const abc v )
{
    const std::map< abc, std::string > values =
        boost::assign::map_list_of( A, "A" )( B, "B" )( C, "C" );
    std::map< abc, std::string >::const_iterator it = values.find( v );
    if ( values.end() == it )
    {
        std::stringstream ss;
        ss << "invalid value (" << static_cast< int >( v ) << ")";
        return ss.str();
    }
    return it->second;
}
int main()
{
    const abc a = A;
    const abc b = B;
    const abc c = C;
    const abc d = static_cast< abc >( 123 );
    std::cout<<"a="<<GetName(a)<<std::endl;
    std::cout<<"b="<<GetName(b)<<std::endl;
    std::cout<<"c="<<GetName(c)<<std::endl;
    std::cout<<"d="<<GetName(d)<<std::endl;
}

从语义和概念上以及就神圣标准而言,它每次都会被创建。

剩下的取决于你的编译器以及你如何支持她:

编译器可能会内联调用,然后将推导出的不变量移到外部到单个初始化点。

编译器可能不喜欢函数有外部链接,所以不内联它,所以很难从其他函数中看到这个不变量。

编译器可能总是检查变量常量并使用一次性初始化当它可以查看内部并验证boost::assign::map_list_of( A, "A" )( B, "B" )( C, "C" )不会改变全局状态。

许多因素,唯一可以确定的方法是查看生成的代码。


响应报价请求:

3.7.2.3[基本.std.auto]:

如果一个命名的自动对象有初始化或有副作用的析构函数,则在其块结束前不得将其销毁,也不得将其作为优化消除,即使它看起来未使用,除非类对象或其副本可以按照"

这基本上意味着,要么它有副作用,在这种情况下它不会被消除,要么它没有,在那种情况下它在C++中很难观察到;这意味着有效地:

观察到的行为总是,就好像每次都调用它一样

换句话说:无法保证初始化只在自动存储中发生一次,因此永远不要假设相反的情况

为什么不使用函子?

#include <iostream>
#include <sstream>
#include <map>
#include <string>
#include <boost/assign/list_of.hpp>

enum abc
{
    A = 1,
    B,
    C
};
class LookupTable
{
    typedef std::map<abc, std::string> map_type;
public:
    LookupTable(const map_type &values)
    : table(values)
    {}
    std::string operator()(abc v) const
    {
         map_type::const_iterator it = table.find(v);
         if (table.end() == it)
         {
             std::stringstream ss;
            ss << "invalid value (" << static_cast< int >( v ) << ")";
            return ss.str();
         }
         return it->second;
    }
private:
    const map_type table;
};

int main()
{
    std::map<abc, std::string> values = boost::assign::map_list_of( A, "A" )( B, "B" )( C, "C" );
    LookupTable GetName(values);
    const abc a = A;
    const abc b = B;
    const abc c = C;
    const abc d = static_cast< abc >( 123 );
    std::cout<<"a="<<GetName(a)<<std::endl;
    std::cout<<"b="<<GetName(b)<<std::endl;
    std::cout<<"c="<<GetName(c)<<std::endl;
    std::cout<<"d="<<GetName(d)<<std::endl;
}