Конструкторы значений карты STL - PullRequest
3 голосов
/ 22 сентября 2010

У меня есть класс X, который я хотел бы поместить в карту STL типа std :: map. Карта STL должна где-то хранить X в памяти, поэтому я ищу эффективный (время выполнения и память) способ создания X и его сохранения на карте.

Я заметил, что следующий код, где x - это объект типа X, а stlMap - это карта типа std :: map:

stlMap["test"] = x;

В результате вызывается следующее:

  1. X конструктор по умолчанию
  2. X Копировать конструктор
  3. Конструктор X Copy
  4. X деструктор
  5. X деструктор
  6. X конструктор присваивания
  7. X деструктор

Почему создается так много X-объектов?

Это неэффективное использование времени и памяти?

Есть ли лучший способ поместить объект на карту? Может быть, изменив карту, чтобы она была картой строк на x *?

Ответы [ 5 ]

5 голосов
/ 22 сентября 2010

Попробуйте stlMap.insert( map<string, X>::value_type("test", x) ):

#include <iostream>
#include <string>
#include <map>

using namespace std;

class X
{
public:
X() { cout << "X default constructor" << endl; }
~X() { cout << "X destructor" << endl; }
X( const X& other ) { cout << "X copy constructor" << endl; }
X& operator=( const X& other ) { cout << "X copy-assignment operator" << endl; }
int x;
};


int main()
{
X x;
map< string, X > stlMap;

cout << "INSERT BEGIN" << endl;
stlMap.insert( map< string, X >::value_type( "test", x ) );
cout << "INSERT END" << endl;
stlMap.clear();
cout << "ASSIGN BEGIN" << endl;
stlMap["test"] = x;
cout << "ASSIGN END" << endl;

return 0;
}

На моем g ++, который сокращает до:

  1. Конструктор X-копирования
  2. Конструктор X-копирования
  3. X деструктор

РЕДАКТИРОВАТЬ: По предложению АрунСаха, обновил тест. Вывод insert () не изменяется, а последовательность присваивания выглядит следующим образом:

  1. X конструктор по умолчанию
  2. Конструктор X-копирования
  3. Конструктор X-копирования
  4. X деструктор
  5. X деструктор
  6. X оператор копирования
3 голосов
/ 22 сентября 2010

Контейнеры STL имеют семантику копирования, поэтому то, что вы наблюдаете, типично.

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

1 голос
/ 22 сентября 2010

Используя это как ссылку:

#include <iostream>
#include <map>

class X
{
    public:
     X()                    { std::cout << "Default Construct\n";}
    ~X()                    { std::cout << "Destroy\n";}
     X(X const&)            { std::cout << "Copy Construct\n";}
     X& operator=(X const&) { std::cout << "Assignment\n";}
};


int main()
{
    std::map<int,X>     store;
    X                   x;
    X                   y;

    std::cout << "Inserting x\n";
    store[1]    = x;
    std::cout << "Finished Insert\n";
    std::cout << "Inserting y\n";
    store[1]    = y;
    std::cout << "Finished Insert\n";
}

При выполнении мы получаем следующий вывод:

Default Construct                    Building X
Default Construct                    Building Y
Inserting x                          ---- Start of an insert
Default Construct                    -------- Work to insert an item that is not in the map
Copy Construct                        
Copy Construct                       
Destroy                              
Destroy                             -------- Finished work to insert a new item
Assignment                          Assign x into the internal object
Finished Insert                     ---- Done
Inserting y                         ---- Start of an insert
Assignment                          Assign y onto the internal object.
Finished Insert                     ---- Done
Destroy                             Destroy y
Destroy                             Destroy x
Destroy                             Destroy map containing one X
0 голосов
/ 22 сентября 2010

Отличается ли порядок построения и разрушения при включении оптимизации?Многие компиляторы могут опускать временные объекты, участвующие в таких операторах при оптимизации.Я предполагаю, что вывод будет включать меньше объектов при оптимизации.

C ++ 0x значительно улучшает ситуацию с конструкторами перемещения .Если в вашем классе X есть конструктор перемещения (который будет выглядеть как X x(X&& m) { ... }, то вы можете изменить свой оператор на stlMap["test"] = std::move(x);. Этот оператор по сути эквивалентен построению одного X и его перемещению в собственность карты.некоторые статьи о C ++ 0x перемещают семантику, если вы не знаете, это полезный материал.

0 голосов
/ 22 сентября 2010

STL работает на основе копирования и присвоения. Таким образом, ожидается некоторое количество копирования и назначения. На вопрос, почему так много, один из способов найти это поставить точки останова на соответствующие позиции в X коде и запустить программу в отладчике.

На текущий момент std::map выполняет управление памятью для X. Если вы переключитесь на X*, то вам придется самостоятельно управлять памятью. Я считаю, что первое подходит в большинстве случаев.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...