Как добавить объект с дорогим 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.