как заставить карту stl создавать/разрушать вставленный объект только однажды

Я нашел очень наносящий ущерб факт о картах 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

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

6
задан Alberto Toglia 6 June 2010 в 16:46
поделиться

5 ответов

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

Код:

#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
6
ответ дан 8 December 2019 в 15:59
поделиться

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

1
ответ дан 8 December 2019 в 15:59
поделиться

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

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

4
ответ дан 8 December 2019 в 15:59
поделиться

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

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

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

Edit

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

2
ответ дан 8 December 2019 в 15:59
поделиться

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

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

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

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

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
ответ дан 8 December 2019 в 15:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: