Является ли STL-вектор вызовом деструктора не-выделенного объекта?

В следующем коде вывод не ожидается:

class test
{
    public:
    test()
    {
        std::cout << "Created" << (long)this << std::endl;
    }
    ~test()
    {
        std::cout << "Destroyed" << (long)this << std::endl;
    }
};

int main(int argc, char** argv)
{
    std::vector<test> v;
    test t;
    v.push_back(t);

    return EXIT_SUCCESS;
}

При выполнении он показывает:

Created-1077942161
Destroyed-1077942161
Destroyed674242816

Я думаю, что второго выхода "Destroyed" не должно быть. Когда я не использую вектор, результатом будет одна Созданная и одна Разрушенная строка, как и ожидалось. Это нормальное поведение?

(Это скомпилировано с помощью GCC в системе FreeBSD)

Ответы

Ответ 1

Все так, как должно быть: есть локальная переменная t, которая создается и затем уничтожается в конце main(), а там v[0], которая создается и уничтожается в конце main().

Вы не видите создание v[0], потому что это происходит при копировании или перемещении конструктора, который ваш тестовый класс не предоставляет. (Таким образом, компилятор предоставляет один для вас, но без вывода.)


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

Ответ 2

#include <cstdlib>
#include <vector>
#include <iostream>

class test
{
    public:
    test()
    {
        std::cout << "Created " << (long)this << std::endl;
    }
    test( const test& )
    {
        std::cout << "Copied " << (long)this << std::endl;
    }
    ~test()
    {
        std::cout << "Destroyed " << (long)this << std::endl;
    }
};

int main(int argc, char** argv)
{
    std::vector<test> v;
    test t;
    v.push_back(t);

    return EXIT_SUCCESS;
}

Вывод:

Created -1076546929
Copied 147865608
Destroyed -1076546929
Destroyed 147865608

std::vector::push_back копирует объект t, вы можете увидеть, что конструктор копирования вызывается указанным выше кодом.

Ответ 3

Вектор держит копию t, поэтому после вызова push_back у вас есть две версии t... одна в стеке и одна в векторе. Поскольку векторная версия была создана копировальным устройством, вы не видите приглашение "Создано..." для этого объекта... но оно все равно должно быть уничтожено, когда векторный контейнер выходит из области видимости, поэтому вы получаете два Сообщения "Уничтоженные...".