как получить карту STL для создания / уничтожения вставленного объекта только один раз - PullRequest
6 голосов
/ 06 июня 2010

Я обнаружил очень вредный факт о картах STL. По какой-то причине я не могу получить объекты, вставленные в карту, чтобы они были построены / уничтожены только один раз.

Пример:

struct MyObject{
    MyObject(){
        cout << "constructor" << endl;
    }
    ~MyObject(){
        cout << "destructor" << endl;
    }
};
int main() {
    std::map<int, MyObject> myObjectsMap;
    myObjectsMap[0] = MyObject();
    return 0;
}

возвращается:

constructor
destructor
destructor
constructor
destructor

Если я это сделаю:

typedef std::pair<int, MyObject> MyObjectPair;
myObjectsMap.insert( MyObjectPair(0,MyObject()));

возвращается:

constructor
destructor
destructor
destructor

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

Ответы [ 5 ]

6 голосов
/ 06 июня 2010

Я предлагаю вам добавить конструктор копирования - я думаю, именно это и используется для «отсутствующих» конструкций.

Код:

#include <iostream>
#include <map>

using namespace std;

struct MyObject{
    MyObject(){
        cout << "no-arg constructor" << endl;
    }
    MyObject(const MyObject&) {
    cout << "const copy constructor" << endl;
    }
    ~MyObject(){
        cout << "destructor" << endl;
    }
};
int main() {
    std::map<int, MyObject> myObjectsMap;
    myObjectsMap[0] = MyObject();
    return 0;
}

Вывод:

no-arg constructor
const copy constructor
const copy constructor
destructor
destructor
no-arg constructor
destructor
destructor
4 голосов
/ 06 июня 2010

std::map разрешено делать столько копий ваших объектов, сколько пожелает. Это определяется реализацией, и вы не можете это контролировать. Кстати, «отсутствующие» конструкции, которые вы заметили, могут быть вызваны конструктором копирования, который вы не определили.

Однако вы можете использовать навесной вес, поэтому создание объекта фактически выбирает существующий объект из пула ранее существующих объектов, а уничтожение объекта ничего не дает. Пул никогда не освобождает свои объекты, но он всегда поддерживает управление ими. Таким образом, объем используемой памяти от начала и до конца велик, но он мало что меняет на протяжении всей жизни программы.

2 голосов
/ 06 июня 2010

Когда вы говорите myObjectsMap [0], вы вызываете конструктор по умолчанию для MyObject. Это потому, что в [0] еще ничего нет, а вы просто получили к нему доступ. Это в руководстве .

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

Поскольку вы позволили компилятору определять ваш конструктор копирования, вы видите больше деструктора, чем сообщений конструктора. (Может быть только один деструктор, но много конструкторов, в отличие от строительства дома.) Если ваш объект никогда не должен копироваться таким образом, то вы, вероятно, захотите объявить частный конструктор копирования и оператор копирования. 1009 *

Вы вызываете конструктор по умолчанию и конструктор копирования дважды каждый с этим кодом:

myObjectsMap[0] = MyObject();

Когда вы делаете это:

myObjectsMap.insert( MyObjectPair(0,MyObject()));

Вы вызываете конструктор по умолчанию один раз, а конструктор копирования 3 раза.

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

note: tests were done using GCC 3.4.5 on a Windows NT 5.1 machine.
2 голосов
/ 06 июня 2010

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

Тем не менее, если (как показывает ваш пример кода) вам просто нужен созданный по умолчанию объект, вставленный в карту, вы можете просто использовать operator [] для его побочного эффекта:

// Insert default constructed MyObject at key 0
myObjectsMap[0];

Редактировать

Мне не совсем понятно из вашего вопроса, но если вы не уверены в количестве построенных объектов и считаете, что имеется несоответствие конструктора / деструктора, обратите внимание, что компилятор предоставит конструктор копирования, который не регистрируется в std::cout, поскольку вы не предоставляете объявленный пользователем.

1 голос
/ 06 июня 2010

Вот так map и другие контейнеры работают, вы не можете обойти это. Вот почему std::auto_ptr нельзя использовать в коллекции, например.

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