2016-06-09 18 views
7

È possibile forzare std::make_shared per utilizzare il nuovo operatore di una classe? Questo si riferisce a un altro SO question. In base a tale domanda, std::make_shared utilizza un allocatore personalizzato:È possibile forzare `std :: make_shared` per usare il nuovo operatore di una classe?

Dalla standard (§20.7.2.2.6 creazione shared_ptr):

Effetti: Alloca memoria adatto a un oggetto di tipo T e costruisce un oggetto in quella memoria tramite il posizionamento nuova espressione :: new (pv) T (std :: forward (args) ...).

Come tale, ho pensato che avrei potuto usare un posizionamento personalizzato nuovo operatore, ma che sembra essere falso

// std::cout 
#include <iostream> 

// std::make_shared 
#include <memory> 

// Track what we're making 
struct Foo { 
    Foo() { 
     std::cout << "Foo constructor" << std::endl; 
    } 
    Foo(Foo const & foo) { 
     std::cout << "Foo copy constructor" << std::endl; 
    } 
    Foo(Foo && foo) { 
     std::cout << "Foo move constructor" << std::endl; 
    } 
    Foo & operator = (Foo const & foo) { 
     std::cout << "Foo copy assignment" << std::endl; 
     return *this; 
    } 
    Foo & operator = (Foo && foo) { 
     std::cout << "Foo move assignment" << std::endl; 
     return *this; 
    } 
    void * operator new(std::size_t size) throw(std::bad_alloc) { 
     std::cout << "Foo new" << std::endl; 
     return ::operator new(size); 
    } 
    void * operator new(std::size_t size, void * p) throw() { 
     std::cout << "Foo placement new" << std::endl; 
     return ::operator new(size,p); 
    } 
    void* operator new (std::size_t size, std::nothrow_t const & nothrow_value) 
     throw() 
    { 
     std::cout << "Foo nonthrowing new" << std::endl; 
     return ::operator new(size,nothrow_value); 

    } 
    void operator delete(void * p, std::size_t size) { 
     std::cout << "Foo delete" << std::endl; 
     ::operator delete(p); 
    } 
    ~Foo() { 
     std::cout << "Foo destructor" << std::endl; 
    } 
}; 

int main() { 
    std::cout << "---Creating foo" << std::endl; 
    auto foo = std::make_shared <Foo>(); 
    std::cout << "---Creating foo2" << std::endl; 
    auto foo2 = std::shared_ptr <Foo> (new Foo()); 
    std::cout << "---Creating foo3" << std::endl; 
    auto foo3 = std::allocate_shared <Foo> (std::allocator <Foo>()); 
    std::cout << "---fin" << std::endl; 
} 

che dà

---Creating foo 
Foo constructor 
---Creating foo2 
Foo new 
Foo constructor 
---Creating foo3 
Foo constructor 
---fin 
Foo destructor 
Foo destructor 
Foo delete 
Foo destructor 

nascosto anche in c'era un tentativo forzare un allocatore che chiamerebbe il nuovo operatore personalizzato con la chiamata a std::allocate_shared. In ogni caso, c'è un modo per rendere std::make_shared chiamare i nuovi operatori personalizzati senza definire un allocatore completamente nuovo?

+7

Non personalizzato nuovo (che controlla la propria allocazione) e 'make_shared' (non eseguendo una seconda allocazione per il proprio tipo) hanno obiettivi opposti? – Barry

+4

Nota che 'make_shared' ha un'allocazione invece di 2 per il * blocco di conteggio *. – Jarod42

+3

Il testo standard che si cita dice esplicitamente che usa ':: new', cioè quello globale e non quello personalizzato. –

risposta

12

No, questo non è possibile (con make_shared).

Dal momento che un allocatore personalizzato per la classe T sarà tipicamente scritto e ottimizzato (per esempio con una piscina) ad aspettarsi allocazioni di dimensioni T e make_shared saranno allocare più la memoria di questo, immagino che non si è ritenuto una caratteristica importante da sostenere.

Inoltre, lo standard fornisce allocate_shared per il caso in cui si desidera utilizzare un allocatore personalizzato.

1

Sort of.

Quello che si fa invece è creare una struttura contenente memoria allineata con un distruttore personalizzato che pulisce l'oggetto e un bool che dice se è necessario farlo.

Quindi posizionare nuovamente la memoria allineata.

Ora utilizzare il costruttore di ptr condiviso con aliasing per restituire un puntatore alla memoria allineata come un tipo diverso.

Problemi correlati