Как добавить объект с дорогим dtor в вектор без emplace_back()

У меня есть объект RenderBuffer это создает буфер OpenGL как часть его конструктора и уничтожает его как часть его деструктора. Это очень дорогая операция. Этот объект не имеет конструктора по умолчанию, поэтому он обычно либо помещается в список инициализации, либо помещается в конец вектора, если их много:

Window::Window(Renderer & render)
    : m_renderBuffer(render) // sometimes looks like this
{
    m_multipleBuffer.push_back(RenderBuffer(render)) // othertimes can look like this
}

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

Я использую VS2010, в котором отсутствует emplace_back() это сделало бы эту работу. Что я могу сделать? Должен ли я отказаться от стиля кодирования RAII и дать моим классам init(...) метод? Есть ли способ заставить это работать с конструкторами копирования? И если так, то стоит ли затрачивать усилия на простое использование методов инициализации (конструкторы перемещения для каждого класса были бы много шаблонными)?

2 ответа

Решение

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

Эта техника была описана Бьярном Страуструпом в его лейтмотиве на Going Native 2012, когда его спросили, как разработчики C++ реализовали переходы до C++11.

Кроме того, хотя я не работал с этой конкретной библиотекой, есть Boost.Move, который эмулирует семантику перемещения для компиляторов C++03. Подвижные классы получают специальные конструкторы перемещения и операторы присваивания перемещения, которые отличаются наличием BOOST_RV_REF(T) аргумент и которые называются с помощью T a(boost::move(b)) или же T a = boost::move(b),

Попробуйте использовать вектор умных указателей на объект. Например:

vector<shared_ptr<RenderBuffer> >  m_multipleBuffer;

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

Обратите внимание, что конструктор копирования также может быть дорогостоящей операцией, если только RenderBuffer не предназначен для совместного использования базового буфера OpenGL.

Другие вопросы по тегам