Есть ли в C ++ умный указатель, такой как unique_ptr, с «destruct перед построением»? семантика?

проблема

Рассмотрим этот простой класс:

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: Теперь пересылаем «Аргументы» правильно.

1

Решение

В C ++ по возможности избегают разрушения старого состояния перед созданием нового состояния, так как нельзя обеспечить гарантию сильных исключений таким образом: «Операция завершена успешно или выдает исключение ничего не меняяMsgstr «Таким образом, в стандартной библиотеке такого нет (я даже не могу назвать фреймворк, добавляющий его).

Хотя наивные и неправильные конструкторы копирования иногда делают это.
Если вы сознательно хотите получить такое поведение, нет ничего лучше, чем написать его для себя.
Но убедитесь, что это именно то, что вы хотите, и запишите это для потомков.

Ваш ResourceManager кажется, в основном делать то, что вы хотите.
Тем не менее, убедитесь, что имя метода / имя класса явно вызывает ваше нестандартное поведение (ни ResourceManager ни replace достаточно конкретны).

5

Другие решения

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

2

Вы можете использовать непопулярный в 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"));
2
По вопросам рекламы [email protected]