Предположим, у меня есть объект с элементом, который дорого построить, и потребность в reset()
функция, которая сбрасывает его в исходное состояние:
struct Example
{
// option 1: efficient, but need to duplicate initialization logic of reset()
Example(int param) : expensive_member_(param), param_(param)
{
}
/* option 2: less code, but initializes expensive_member_ twice
Example(int param) : param_(param)
{
reset();
}*/
void reset()
{
expensive_member_ = ClassWithExpensiveConstructor(param_);
}
ClassWithExpensiveConstructor expensive_member_;
int param_;
}
Есть ли лучший способ / шаблон для эффективного сброса объекта в исходное состояние без дублирования логики инициализации в списке инициализатора и reset
функционировать?
редактировать: Если нет общего способа достичь того, чего я хочу, это также является приемлемым результатом этого вопроса!
Вы можете сделать свой ExpensiveMember
указатель, в таком случае ваш вариант 2 не будет вызывать ExpensiveMember
конструктор в Example
конструктор, если вы явно не вызываете его:
struct Example
{
Example(int param) : expensive_member_(), param_(param)
{
reset();
}
~Example() {
delete expensive_member_; // better use unique_ptr etc
}
// Also a copy constructor and assignment operator
// are needed to avoid memory problems such as double-delete.
// Also, better use unique_ptr etc.
// This answer does not use unique_ptr just to make the main idea more clear.
void reset()
{
delete expensive_member_; // better use unique_ptr etc
expensive_member_ = new ClassWithExpensiveConstructor(param_);
}
ClassWithExpensiveConstructor* expensive_member_; // better use unique_ptr etc
int param_;
}
Если ClassWithExpensiveConstructor
это тот класс, чья конструкция / сброс дорогая, именно она должна оптимизировать работу.
Другим вариантом будет сохранить копию начального значения в const
член, предполагая, что копирование конструкции / назначения не дорого. Это будет использовать больше памяти, но улучшить производительность, если вы звоните Example::reset()
много.
struct Example
{
Example(int param)
: expensive_member_backup_(param)
, expensive_member_(expensive_mamber_backup)
, param_(param)
{
}
void reset()
{
expensive_member_ = expensive_member_backup_;
}
const ClassWithExpensiveConstructor expensive_member_backup_;
ClassWithExpensiveConstructor expensive_member_;
int param_;
}
Простым решением было бы использование (интеллектуального или обычного) указателя, так что стоимость инициализации элемента (то есть указателя) становится меньше, а фактический объект инициализируется только при вызове reset()
:
struct Example
{
Example(int param) : param_(param)
{
reset();
}
void reset()
{
p.reset(new ClassWithExpensiveConstructor(param_));
}
unique_ptr<ClassWithExpensiveConstructor> p;
int param_;
}