отложенная инициализация? - PullRequest
0 голосов
/ 28 октября 2011

Может кто-нибудь объяснить, почему это происходит?Я написал следующее:

1) класс WindowManager, который реализован как синглтон и имеет метод Instance(), определенный следующим образом:

static WindowManager * instance_;
//...
WindowManager * WindowManager::instance_ = 0;
WindowManager & WindowManager::Instance()
{
    if (!instance_)
        instance_ = new WindowManager();
    return *instance_;
}

2) a WindowManager::createWindowметод, который возвращает ссылку на недавно созданное окно, определенное так:

Window & WindowManager::createWindow()
{
    windows_.push_back(Window());
    return windows_.at(windows_.size() - 1);
}

3) метод Window::print, который печатает сообщение внутри окна

В моей основной программе янаписали следующее:

ui::Window & win1 = ui::WindowManager::Instance().createWindow();
ui::Window & win2 = ui::WindowManager::Instance().createWindow();
win1.print("First window");
win2.print("Second window");

Это не работает!Выполняется только второй вызов print (для win2).Однако, если я изменю порядок, например, так:

ui::Window & win1 = ui::WindowManager::Instance().createWindow();
win1.print("First window");
ui::Window & win2 = ui::WindowManager::Instance().createWindow();
win2.print("Second window");

, тогда все будет работать как положено.Если бы кто-нибудь мог пролить свет на эту ситуацию, любая помощь будет принята с благодарностью.

1 Ответ

2 голосов
/ 28 октября 2011

Вот краткий пример, иллюстрирующий проблему:

#include <iostream>
#include <vector>
using namespace std;

struct T
{
    int id;
    T(int id) : id(id)
       { cout << "created " << id << endl; }
    T(T const& t) : id(t.id)
       { cout << "copy: " << t.id << endl; }
    void print(char const* m)
       { cout << id << ": " << m << endl; }
};

vector<T> ts;

T& create(int id)
{
    ts.push_back(T(id));
    return ts.at(ts.size() - 1);
}

int main()
{
    // Uncomment these lines and compare results
    //int const max_windows = 10;
    //ts.reserve(max_windows);

    T& t1 = create(1);
    T& t2 = create(2);
    t1.print("t1");
    t2.print("t2");
}

Скомпилируйте и запустите как есть и посмотрите, что выводится на стандартный вывод. Затем раскомментируйте reserve() вызов, скомпилируйте и запустите еще раз и сравните с предыдущим выводом.

Проблема в том, что std::vector::push_back вызывает перераспределение данных внутри страны. Это делает недействительными все ссылки, указатели или итераторы на векторные элементы, которые вы получили до перераспределения.

...