std::unique_ptr::reset(x) vs przypisanie nowej wartości używając std::make_unique(x) - jakieś różnice?

0

hej,
jak w tytule ciekawi mnie czy są jakieś znaczne różnice pomiędzy przypisaniem nowej wartości do wskaźnika poprzez użycie make_unique<>() albo resetowanie go i przekazywanie mu nowej wartości poprzez parametr:

auto x{std::make_unique<int>(1)};
//pozniej...
x = std::make_unique<int>(2);

albo:

auto x{std::make_unique<int>(1)};
x.reset(new int(3)); 

Jakie są w ogóle realne przypadki resetowania wskaźnika? Nigdy nie było mi to potrzebne.
Tak swoja droga co myślicie o czymś takim:

x.reset(std::make_unique<int>(3).release());

Ma to jakiś sens? Czy zbędne zaciemnianie kodu?

2

Resetowanie wskaźnika jest przydatne wtedy kiedy go potrzebujesz. Ciężko to jakoś bardziej uzasadnić, jak nie miałeś potrzeby jego użycia to znaczy, że nie spotkałeś się z taką - rzeczywiście dość rzadką - sytuacją. Możesz np. chcieć przypisać kiedyś wskaźnikowi inną wartość, lub kompletnie usunąć obecną.

Jeśli chodzi o ostatni przykład - kompletny bezsens, nie zyskujesz nic poza odrzuceniem na code review.

3

Możesz chcieć zwolnić pamięć wskaźnika nie wychodząc z zasięgu.

auto up = std::make_unique<Foo>();
// ...
up.reset(nullptr);
3

haha bez jaj, tworzenie unikalnego wskaźnika tylko po to, aby od razu oddać posiadaną wartość :) - WTF

2
Cyberah napisał(a):

haha bez jaj, tworzenie unikalnego wskaźnika tylko po to, aby od razu oddać posiadaną wartość :) - WTF

Możesz sobie stworzyć sprytny wskaźnik na zapas, a zmienić mu unikalną wartość później.

std::unique_ptr<int> p;
// ...
p.reset(new int(5));

Zajrzałem do "Skuteczny nowoczesny C++" Meyersa i jak się okazuje są (oczywiście) jakieś śmieszne subtelności w związku z przekazywaniem doskonałym. Przykład jest podany ze std::vector, który ma zarówno konstruktor akceptujący std::initializer_list (std::vector<int>{10, 1} tworzy wektor dwóch elementów, {10, 1}) jak i parę wartości (std::vector<int>(10, 1) tworzy wektor 10 elementów o wartości 1). Załóżmy teraz, że mamy ten sprytny wskaźnik na taki wektor:

std::unique_ptr<std::vector<int>> v;

I teraz chcemy go zastąpić wektorem, który ma dwa elementy, {10, 20}. Wywołanie

v = std::make_unique<std::vector<int>>(10, 20);

Tworzy wektor 10 elementów, bo wywołuje tamten konstruktor. Wywołanie

v = std::make_unique<std::vector<int>>({10, 20});

Wyburacza się. Można zrobić tak:

auto initList = { 10, 20 };
v = std::make_unique<std::vector<int>>(initList);

Ale to ma dwie linijki ;). Natomiast przy reset wywołujemy konstruktor jawnie, więc można zrobić:

v.reset(new std::vector<int>{10, 20});

Pełen kod testowy:

#include <memory>
#include <vector>
#include <iostream>

int main () {
    std::unique_ptr<std::vector<int>> v;

    v = std::make_unique<std::vector<int>>(10, 20);
    std::cout << v->size() << std::endl; // 10

    // v = std::make_unique<std::vector<int>>({10, 20});
    // błąd kompilacji

    auto initList = { 10, 20 };
    v = std::make_unique<std::vector<int>>(initList);
    std::cout << v->size() << std::endl; // 2


    v.reset(new std::vector<int>{10, 20});
    std::cout << v->size() << std::endl; // 2

    v.reset(new std::vector<int>(10, 20));
    std::cout << v->size() << std::endl; // 10
}

Po szczegóły odsyłam do punktu 21 wyżej wymienionej książki. Którą to kiedyś trzeba by znowu przeczytać :(

1 użytkowników online, w tym zalogowanych: 0, gości: 1