Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Hasło nie zostało zweryfikowane
Niniejsze hasło zostało opracowane, jednak nie zostało ono zweryfikowane przez administrację serwisu. Jeżeli znalazłeś błędy merytoryczne w niniejszym dokumencie, prosimy o ich zgłoszenie na forum w dziale Znalezione błędy.
Opracował: baziorek
Język C++

make_unique

[szablon funkcji] Funkcja zwracająca inteligentny wskaźnik std::unique_ptr<T> zaalokowanym obiektem lub tablicą obiektów danego typu.

Składnia

C/C++
#include <memory>
namespace std
{
    template < class T, class...Args >
    unique_ptr < T > make_unique( Args &&...args );
   
    template < class T >
    std::unique_ptr < T[] > make_unique( std::size_t size );
   
    template < class T, class...Args >
    /* unspecified */ make_unique( Args &&...args ) = delete;
}

Parametry szablonu

ParametrOpis
Ttyp obiektu zarządzanego przez inteligentny wskaźnik
...Argsargumenty konstruktora obiektu zarządzanego przez inteligentny wskaźnik, są one przekazywane przez przekazywanie doskonałe

Argumenty

ArgumentOpis
Args&&... argsargumenty konstruktora tworzonego obiektu typu T
sizeilość elementów typu T w tablicy zarządzanej przez inteligentny wskaźnik. T musi być typem znanym w momencie użycia

Zwracana wartość

Zależnie od wersji użytej funkcji dla typu T:
std::unique_ptr < T >
 lub
std::unique_ptr < T[] >
.

Opis szczegółowy

Funkcja zwraca inteligentny wskaźnik
std::unique_ptr < T >
 przekazując podane argumenty do konstruktora typu T. Możemy zaalokować pojedyńczy obiekt typu T, lub dynamiczną tablicę obiektów typu T.

Wg Scotta Meyersa z książki "Skuteczny nowoczesny C++" funkcja
std::make_unique()
 powinna być stosowana zamiast ręcznego tworzenia
std::unique_ptr <>
 i allokacji za pomocą
operator new
 z dwóch powodów:
1. Krótszego zapisu, mniejszej podatności na błędy modyfikacji kodu, mniejszej duplikacji kodu:
C/C++
std::unique_ptr < std::string > text( new std::string );
// vs:
auto text = std::make_unique < std::string >();
2. Większego bezpieczeństwa wątkowego.
Mając funkcję np.:
void saveText( std::unique_ptr < std::string > text, int textDepth );
 i wywułując np.:
saveText( new std::string( "Ala ma świnkę morską" ), computeDepthLevelFromEnvironment() );
 oraz wiedząc, że nie jest zdefiniowana kolejność ewaluacji argumentów funkcji może się zdarzyć sytuacja, że wpierw zaalokujemy obiekt, następnie funkcja computeDepthLevelFromEnvironment() wyrzuci wyjątek -wtedy nastąpi wyciek pamięci. W podobnej sytuacji stosując
std::make_unique
 destruktor obiektu
std::unique_ptr
 posprząta zaalokowaną pamięć.

Dodatkowe informacje

W razie konieczności podania własnego deletera funkcja
std::make_unique()
 tego nie obsługuje, dlatego wtedy musimy utworzyć inteligentny wskaźnik bez użycia funkcji, przykładowo:
C/C++
#include <iostream>
#include <string>
#include <memory>

int main()
{
    auto printingStringDeleter =[]( std::string * text )
    {
        std::cout << "Deleting: '" << * text << "'\n";
        delete text;
    };
   
    std::unique_ptr < std::string, decltype( printingStringDeleter ) > dummyText( new std::string( "Ala ma kota" ), printingStringDeleter );
}
Standardowe wyjście programu:
Deleting: 'Ala ma kota'


Kolejną sytuacją kiedy funkcja sprawia problemy jest używanie inicjatorów klamrowych (inicjatory klamrowe nie mogą być przekazywane doskonale):
C/C++
#include <iostream>
#include <vector>
#include <memory> // std::make_unique
#include <iterator> // std::ostream_iterator
#include <algorithm> // std::copy()


int main()
{
    //     auto vectorPtr = std::make_unique<std::vector<int>>({1, 3, 5}); // tutaj będzie błąd kompilacji
    //     std::cout << "\nvector.size() = " << vectorPtr->size() << ", elements: ";
    //     std::copy(vectorPtr->cbegin(), vectorPtr->cend(), std::ostream_iterator<int>(std::cout, ", "));
   
    auto valuesToInitialise = { 1, 3, 5 };
    auto vectorPtr = std::make_unique < std::vector < int >>( valuesToInitialise );
    std::cout << "\nvector.size() = " << vectorPtr->size() << ", elements: ";
    std::copy( vectorPtr->cbegin(), vectorPtr->cend(), std::ostream_iterator < int >( std::cout, ", " ) );
   
    std::cout << std::endl;
}
Standardowe wyjście programu:
vector.size() = 3, elements: 1, 3, 5,

Rzucane wyjątki

Funkcja może wyrzucić te same wyjątki, które może wyrzucić konstruktor obiektu typu T. Może również być wyrzucony
std::bad_alloc
 w razie braku pamięci.

Wymagania

Kompilator zgodny przynajmniej z C++14 powinien dostarczyć funkcję
std::make_unique()
.
Jeśli nasz kompilator jej nie posiada, a posiada
std::unique_ptr <>
 możemy użyć przykładowej implementacji z tego artykułu. W ostateczności możemy użyć inteligętnego wskaźnika z biblioteki boost:  boost::make_unique.

Implementacja

Zaczerpnięta z En.cppreference.com:
C/C++
template < typename T, typename...Arg >
std::unique_ptr < T > make_unique( Arg &&...args )
{
    return std::unique_ptr < T >( new T( std::forward < Arg >( args )...) );
}

Przykład

C/C++
#include <iostream>
#include <vector>
#include <memory> // std::make_unique
#include <iterator> // std::ostream_iterator
#include <algorithm> // std::copy()

int main()
{
    auto vectorPtr = std::make_unique < std::vector < int >>();
    std::cout << "vector.size() = " << vectorPtr->size() << ", elements: ";
    std::copy( vectorPtr->cbegin(), vectorPtr->cend(), std::ostream_iterator < int >( std::cout, ", " ) );
   
    vectorPtr = std::make_unique < std::vector < int >>( 2, 3 );
    std::cout << "\nvector.size() = " << vectorPtr->size() << ", elements: ";
    std::copy( vectorPtr->cbegin(), vectorPtr->cend(), std::ostream_iterator < int >( std::cout, ", " ) );
   
    std::cout << std::endl;
}
Standardowe wyjście programu:
vector.size() = 0, elements:
vector.size() = 2, elements: 3, 3,

Zagadnienia powiązane

auto_ptrPrzechowuje wskaźnik na zaalokowany obiekt zapewniając jednocześnie jego zwolnienie z chwilą wywołania destruktora. (szablon klasy)
shared_ptrPrzechowuje wskaźnik i kontroluje liczbę istniejących kopii wskaźnika (automatycznie zwalnia pamięć). (szablon klasy)
scoped_ptrAutomatycznie zwalnia pamięć zaalokowaną przy pomocy operatora
new
 przy wyjściu ze scope-a. (szablon klasy)

Linki zewnętrzne

Linki zewnętrzne