Рассмотрим этот простой класс:
struct C {
C(const char* name) : name(name) {
cout << "constructing " << name << endl;
}
~C() {
cout << "destructing " << name << endl;
}
string name;
};
Я хотел бы иметь указатель на экземпляр этого класса, который обычно заменяется другим экземпляром. Тем не менее, я хотел бы, чтобы текущий экземпляр был уничтожен до новый экземпляр создан.
Если я использую unique_ptr
нормальным образом это не работает:
unique_ptr<C> c( new C("the first one"));
c.reset(new C("the second one"));
(Нежелательно) Вывод:
построение первого
построение второго
разрушая первый
разрушая второй
Желаемый эффект может быть достигнут следующим образом:
unique_ptr<C> c( new C("the first one"));
c.reset(); // explicitly destruct the first one first
c.reset(new C("the second one"));
Выход:
построение первого
разрушая первый
построение второго
разрушая второй
Это моя попытка создать умный указатель с таким поведением.
Такой умный указатель уже существует?
template<typename Resource>
class ResourceManager {
public:
ResourceManager() {}
template<typename... Arguments>
ResourceManager(Arguments&&... args) {
replace<Arguments...>(std::forward<Arguments>(args)...);
}
template<typename... Arguments>
void replace(Arguments&&... args) {
resource.reset();
resource.reset(new Resource(std::forward<Arguments>(args)...));
}
private:
unique_ptr<Resource> resource;
};
template<typename Resource, typename... Arguments>
ResourceManager<Resource> make_resource_manager(Arguments... args) {
return ResourceManager<Resource>(args...);
}
int main() {
//ResourceManager<C, const char*> r("first1");
auto r = make_resource_manager<C>("first1");
r.replace("second1");
}
Выход:
построение первого
разрушая первый
построение второго
разрушая второй
РЕДАКТИРОВАТЬ: Перемещен шаблон «Аргументы …» на функциональный уровень.
РЕДАКТИРОВАТЬ 2: Теперь пересылаем «Аргументы» правильно.
В C ++ по возможности избегают разрушения старого состояния перед созданием нового состояния, так как нельзя обеспечить гарантию сильных исключений таким образом: «Операция завершена успешно или выдает исключение ничего не меняяMsgstr «Таким образом, в стандартной библиотеке такого нет (я даже не могу назвать фреймворк, добавляющий его).
Хотя наивные и неправильные конструкторы копирования иногда делают это.
Если вы сознательно хотите получить такое поведение, нет ничего лучше, чем написать его для себя.
Но убедитесь, что это именно то, что вы хотите, и запишите это для потомков.
Ваш ResourceManager
кажется, в основном делать то, что вы хотите.
Тем не менее, убедитесь, что имя метода / имя класса явно вызывает ваше нестандартное поведение (ни ResourceManager
ни replace
достаточно конкретны).
В стандарте ничего такого нет. Я не уверен, почему вы хотите этот конкретный порядок: либо объект все еще жив, и вы можете использовать его повторно, либо вы можете получить новый объект, который не может быть создан, и пустой умный указатель.
Вы можете использовать непопулярный в C ++ препроцессор:
#define REPLACE_C(ptr,new_value) \
do { \
ptr.reset(); \
ptr.reset(new_value); \
while(false)
unique_ptr<C> c( new C("the first one"));
REPLACE_C(c, new C("the second one"));