2016-06-09 9 views
7

Ist es möglich, std::make_shared zu zwingen, den neuen Operator einer Klasse zu verwenden? Dies betrifft eine weitere SO question. Nach dieser Frage verwendet std::make_shared einen benutzerdefinierten Zuordner:Ist es möglich, `std :: make_shared` zu zwingen, den neuen Operator einer Klasse zu verwenden?

Von der Standard (§20.7.2.2.6 Shared_ptr Schaffung):

Effekte: Reserviert Speicher für ein Objekt vom Typ T und konstruiert ein Objekt, in diesem Speicher über die Platzierung neuer Ausdruck :: new (pv) T (std :: forward (args) ...).

Als solche, dachte ich, dass ich eine benutzerdefinierte Platzierung neuer Betreiber verwenden könnte, aber das scheint falsch

// 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; 
} 

zu sein, die

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

auch in ein Versuch war es versteckt gibt Erzwingen eines Zuordners, der den benutzerdefinierten neuen Operator mit dem Aufruf an std::allocate_shared aufrufen würde. Gibt es in jedem Fall eine Möglichkeit, std::make_shared die benutzerdefinierten neuen Operatoren aufzurufen, ohne einen neuen Allokator zu definieren?

+7

Haben nicht benutzerdefinierte neue (Kontrolle Ihrer eigenen Zuordnung) und 'make_shared' (keine zweite Zuweisung für Ihren eigenen Typ) etwas entgegengesetzte Ziele? – Barry

+4

Beachten Sie, dass 'make_shared' eine Zuweisung statt 2 für den * Zählblock * vornimmt. – Jarod42

+3

Der Standardtext, den Sie speziell zitieren, sagt, dass er ':: new' verwendet, d. H. Den globalen, nicht Ihren eigenen. –

Antwort

12

Nein, dies ist nicht möglich (mit make_shared).

Da ein individuelles Allocator für Klasse T wird in der Regel geschrieben und optimiert werden (zum Beispiel mit einem Pool) Zuteilungen von Größe zu erwarten T und make_shared wird als die mehr Speicher werden die Zuteilung, stelle ich mich es nicht gehalten wurde ein wichtiges Feature zur Unterstützung.

Weiter bietet der Standard allocate_shared für den Fall, dass Sie einen benutzerdefinierten Zuordner verwenden möchten.

1

Sortieren von.

Was Sie stattdessen tun, ist eine Struktur zu erstellen, die ausgerichteten Speicher mit einem benutzerdefinierten Zerstörer, der das Objekt aufräumt und ein Bool sagen, wenn Sie dies tun sollten.

Dann Platzierung neu der ausgerichteten Speicher.

Verwenden Sie nun den Alias ​​Shared Ptr-Konstruktor, um einen Zeiger auf den ausgerichteten Speicher als einen anderen Typ zurückzugeben.

Verwandte Themen