2015-07-27 1 views
3

Предположим, что у меня есть объект с членом, который стоит дорого построить, и потребность в 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?

Редактировать: Если нет общего способа достижения того, что я хочу, это также приемлемый результат этого вопроса!

+3

Вы можете дать 'ClassWithExpensiveConstructor' свой собственный метод сброса, который сделает наиболее эффективный сброс. –

+0

Почему бы не сделать road_member_ указателем? – Hcorg

+0

@ JonathanPotter не может просто переместить проблему в другое место? То есть Мне нужно будет беспокоиться о дублированном коде в ClassWithExpensiveConstructor вместо 'Example'? – anderas

ответ

1

Вы можете сделать свой 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_; 
} 
+0

@anderas, исправленный. Не хотел использовать 'unique_ptr' в ответе, так что основная идея (указатель не требует инициализации) не скрыта. – Petr

+2

Better :-) Хотя, нет необходимости проверять на 'nullptr' перед удалением указателя. Не могли бы вы принять решение @ kiviak? У ваших сообщений есть одна и та же основная идея, но он был быстрее, поэтому я думаю, что это будет справедливо. – anderas

+0

@anderas, вы можете принять то, что вам больше нравится, но на самом деле мой ответ раньше ... :) – Petr

1

Если 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_; 
} 
1

простое решение было бы использовать (умный или обычный) указатель, так что стоимость инициализации элемента (то есть указателя) становится меньше, а фактический объект только инициализируется при вызове reset():

struct Example 
{ 
    Example(int param) : param_(param) 
    { 
     reset(); 
    } 

    void reset() 
    { 
     p.reset(new ClassWithExpensiveConstructor(param_)); 
    } 

    unique_ptr<ClassWithExpensiveConstructor> p; 
    int param_; 
} 
+0

Это похоже на лучшую идею, хотя небольшое объяснение было бы приятным, и 'unique_ptr' кажется немного лучше подходит для этой работы (меньше накладных расходов и совместного использования не является необходимо здесь). Не возражаете, если я (или вы) отредактировал ответ соответственно? – anderas

+0

@ anderas, я не умею. Я плохо разбираюсь в умном указателе, но думаю, вы можете использовать его в качестве прокси-шаблона – kiviak

 Смежные вопросы

  • Нет связанных вопросов^_^