Is std::map table initialization optimized?
Considering the example at the end of the question, is the map obje开发者_Go百科ct going to be created every time the function GetName()
is called?
#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;
}
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.
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;
}
精彩评论