Оптимизирована ли инициализация таблицы std :: map? - PullRequest
3 голосов
/ 21 июня 2011

Учитывая пример в конце вопроса, будет ли объект карты создаваться каждый раз, когда вызывается функция 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;
}

Ответы [ 2 ]

5 голосов
/ 21 июня 2011

Семантически и концептуально, а также в отношении Святого Стандарта, он будет создаваться каждый раз.

Остальное зависит от вашего компилятора и от того, как вы его поддерживаете:

Возможно компилятор может встроить вызов, а затем переместить выведенные инварианты за пределы одной точки инициализации,

Возможно компилятору не нравится, что ваша функция имеет внешнюю связь, и поэтому она не встроена в нее, а затем испытывает трудности с просмотром этого инварианта из других функций.

Возможно компилятор всегда будет проверять постоянство переменных и использовать однократную инициализацию, когда он может заглянуть внутрь и убедиться, что boost::assign::map_list_of( A, "A" )( B, "B" )( C, "C" ) не изменяет глобальное состояние.

Множество факторов, и единственный способ убедиться в этом - взглянуть на сгенерированный код.


В ответ на запрос предложения:

3.7.2.3 [basic.std.auto]:

Если именованный автоматический объект имеет инициализацию или деструктор с побочными эффектами, он не должен быть уничтожен до конца своего блока и не должен быть удален какоптимизация, даже если она не используется, за исключением того, что объект класса или его копия могут быть удалены, как указано в "

. Это в основном означает, что либо у него есть побочные эффекты, в этом случае он не будетбыть исключенным или не имеющим, и в этом случае он едва заметен в C ++, это эффективно означает:

Наблюдаемое поведение всегда , как если бы оно вызывалось каждый раз .

Другими словами: Нет способа гарантировать, что инициализация происходит только один раз с автоматическим хранением, поэтому никогда не принимайте обратное .

0 голосов
/ 21 июня 2011

Почему бы не использовать функтор?

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