std::map 表初始化是否优化?

发布于 2024-11-16 13:24:14 字数 1120 浏览 4 评论 0原文

考虑问题末尾的示例,每次调用函数 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;
}

Considering the example at the end of the question, is the map object going to be created every time the function GetName() is called?
Or is the creation going to be optimized away and created as some lookup table?

#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;
}

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

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

发布评论

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

评论(2

﹂绝世的画 2024-11-23 13:24:14

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

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

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

可能编译器不喜欢你的
函数具有外部链接,因此不会内联它,然后就很难了
看到与其他函数的不变性。

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

因素很多,唯一确定的方法就是查看生成的代码。


响应报价请求:

3.7.2.3 [basic.std.auto]:

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

中的指定被消除

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

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

换句话说:没有办法保证自动存储时初始化只发生一次,所以永远不要假设相反的情况

Semantically and conceptually and with respect to The Holy Standard, it will be created every time.

The rest is up to your compiler and how you support her:

Possibly the compiler can inline the call and then move deduced invariants outside
to a single point of initialization.

Possibly the compiler dislikes that your
function has external linkage and so does not inline it, then having a hard time
seeing that invariant from other functions.

Possibly the compiler will always check a variables constness and use one-time-initialization
when it can look inside and verify that boost::assign::map_list_of( A, "A" )( B, "B" )( C, "C" )
does not mutate global state.

Many factors, and the only way to be sure is to look at generated code.


In response to a request for quotation:

3.7.2.3 [basic.std.auto]:

If a named automatic object has initialization or a destructor with side effects, it shall not be destroyed before the end of its block, nor shall it be eliminated as an optimization even if it appears to be unused, except that a class object or its copy may be eliminated as specified in"

This basically means that either it has side effects, in which case it won't be eliminated, or it hasn't, in which case it is hardly observable within C++; this means effectively:

The observed behaviour is always as if it is called every time.

In other words: There is no way to guarantee that initialization only happens once with automatic storage, so never assume the opposite.

梦中的蝴蝶 2024-11-23 13:24:14

为什么不使用函子?

#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;
}

Why not use a functor?

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