2016-05-27 5 views
1

In der Kompilierzeit habe ich das folgende Problem, wie man das kompilieren, weil konzeptionell für mich es richtig ist, sind alle Vorschläge zum Refactoring willkommen.Umgehen Sie einen Vorlage Fehler mit einem privaten Destruktor

Ich habe einen Kompilierfehler, weil Destruktor "Suche" privat ist, aber ich lösche nicht auf einem Suchzeiger, da ich einen benutzerdefinierten Deleter in der Initialisierung der Basisklasse zur Verfügung gestellt habe. Ich weiß, dass der Compiler das nicht weiß, wie man es umgehen kann.

Fehlerbeschreibung: Fehler C2248: kann nicht privat Mitglied in der Klasse deklariert zugreifen 'Suche' Compiler erzeugt hat 'Suchen :: ~ Search' hier

class Search 
{ 
public: 
static Search* New(/* */); // using a pool of already allocated objects to avoid expensive allocations 
    static void Delete(Search*); 

private: 
    Search(/* */) {/* */} 
    ~Search() {/* */} 
}; 


template<class T> 
class MyList 
{ 
    public: 
    typedef (*CustomDeleter) (T* pElement); 

    MyList(CustomDeleter lpfnDeleter = NULL) {}; 


    void Empty() 
    { 
     for (/**/) 
     { 
      if (m_pList[m_nListLastUsed]) 
      { 
       if (m_lpfnCustomDeleter == NULL) 
        delete m_pList[m_nListLastUsed]; // COMPILE ERROR HERE BECAUSE Search destructor is private BUT I won't use that instruction since 
                // I provided a custom Deletern I know that the compiler doesn't know that, how to bypass it 
       else 
        m_lpfnCustomDeleter(m_pList[m_nListLastUsed]); 
      } 
     } 
    } 

    private: 
    T** m_pList; 
    CustomDeleter m_lpfnCustomDeleter; // Pointer to a custom deleter 
}; 

class Query : public MyList<Search> 
{ 
    public: 
    Query() : MyList<Search>(&Search::Delete) // I set a custom deleter since Search hides its destructor : is this the right way ? 
    {} 

    ~Query() 
    { 
     /****/ 
     Empty(); // PROBLEM HERE 
     /***/ 
    } 
}; 
+0

@Holt, weil ich Suchobjekte nicht löschen möchte, möchte ich sie in Lock Free Stack speichern (nach der Reinigung), um später mit New – Aminos

+0

verwendet zu werden, nur weil Sie nicht denken, dass Sie * Anruf * Der Code bedeutet nicht * ungültig * Code kann immer noch existieren. 'delete m_pList [m_nListLastUsed]; 'erwartet einen ordnungsgemäß verfügbaren Destruktor, den Sie nicht zur Verfügung gestellt haben. Somit ist der Code nicht gültig, also dein Fehler. Ich müsste einen Moment darüber nachdenken, ob das mögliche Alternativen hat. – WhozCraig

+1

'm_pList' ist nirgendwo definiert. Bitte posten Sie einen [MCVE] (http://stackoverflow.com/help/mcve) –

Antwort

3

Stellen Sie sicher, dass 'm_lpfnCustomDeleter' nie NULL ist oder besser nullptr. Sie können dies sicherstellen, indem Sie auf einen Standardlöscher zurückgreifen, wenn der Benutzer keinen benutzerdefinierten Löscher bereitstellt.

Ich würde etwas wie unten bevorzugen.

#include <iostream> 

template <typename PointerType> 
struct DefaultDeleter { 
    void operator()(PointerType* ptr) { 
    std::cout << "Delete\n"; 
    } 
}; 

struct CustomDeleter { 
    void operator()(int* ptr) { 
    std::cout << "Custom int deleter" << std::endl; 
    } 
}; 

template <typename T, typename Deleter = DefaultDeleter<T>> 
class Whatever 
{ 
public: 
    Whatever() { 
    std::cout << "Cons\n"; 
    } 
    void deinit() { 
    Deleter d; 
    auto v = new T; 
    d(v); // Just for the sake of example 
    } 
}; 

int main() { 
    Whatever<char> w; 
    w.deinit(); 

    Whatever<int, CustomDeleter> w2; 
    w2.deinit(); 
    return 0; 
} 

aktualisiert :: W/O-Code Refactoring Unter der Annahme, w/o C++ 11

  1. Lassen Sie sich diese kleine Metaprogramm auf Ihre Codebasis hinzugefügt.

    Namespace mein {

     template <typename T, typename U> struct is_same { 
         static const bool value = false; 
         }; 
    
         template <typename T> 
         struct is_same<T, T> { 
         static const bool value = true; 
         }; 
    
         template <bool v, typename T = void> struct enable_if; 
    
         template <typename T = void> struct<true, T> { 
         typedef T type; 
         }; 
    
        } 
    
  2. ändern Leere Funktion:

    Leere Leer() { für (/ **** /) { do_delete(); } }

 
    template <typename = 
        typename my::enable_if<my::is_same<T, Search>::value>::type> 
    void do_delete() { 
     assert (m_lpfnCustomDeleter != NULL); 
     m_lpfnCustomDeleter(m_pList[m_nListLastUsed]); 
    } 

    void do_delete() { 
     delete m_pList[m_nListLastUsed]; 
    } 

Wenn Sie C++ verwenden 11, die Sie nicht die Metaprogramm unter Namespace 'mein' haben zu schreiben. Ersetzen Sie einfach 'my :: is_same' und 'my :: enable_if' durch 'std :: is_same' und 'std :: enable_if'.

Hinweis :, haben den obigen Code nicht kompiliert und getestet.

+0

Der CustomDeleter ist eine Funktion, die ich zu "MyList" hinzugefügt habe, so dass ich den NULL-Standardwert verwendet habe, um die Umgestaltung des alten Codes mit MyList ohne diesen Parameter zu vermeiden. – Aminos

+0

Wenn Sie können, sollten Sie das Design des Codes überdenken. Etwas fühlt sich nicht richtig an. Kannst du mir sagen, was ist 'm_pList'? Wenn es einen Zeiger auf 'Suchen' hält, können Sie es nicht einfach löschen und seinen Destruktor als privat definieren. Oder Sie tun etwas, das dem ähnlich ist, was ich gezeigt habe, und machen 'CustomDeleter' als Freund der Suche. – Arunmu

+0

Anscheinend ist Ihre Lösung ordentlich ... Ich werde das versuchen ... Ansonsten ist MyList eine sortierte Liste, die auch von anderen Klassen verwendet wird ... aber die anderen Klassen haben öffentliche Destruktoren. Ist es jetzt klar? – Aminos

1

Trennen Sie den Code, um das Löschen von dem Rest zu tun:

 if (m_pList[m_nListLastUsed]) 
     { 
      if (m_lpfnCustomDeleter == NULL) 
       delete m_pList[m_nListLastUsed]; // COMPILE ERROR HERE BECAUSE Search destructor is private BUT I won't use that instruction since 
               // I provided a custom Deletern I know that the compiler doesn't know that, how to bypass it 
      else 
       m_lpfnCustomDeleter(m_pList[m_nListLastUsed]); 
     } 

den Code oben Ersetzen durch einen Aufruf:

custom_delete(m_pList[m_nListLastUsed]); 

Dann ist es als eine Methode der Liste Klasse hinzufügen, don‘ t vergessen <type_traits> auch enthalten:

std::enabled_if<std::is_destructible<T>::value, void>::type custom_delete(T* ptr) { 
    /* Note: this isn't pre-2000 anymore, 'lpfn' as a prefix is horrible, 
     don't use prefixes! */ 
    if (m_lpfnCustomDeleter) { 
     m_lpfnCustomDeleter(ptr); 
    } else { 
     delete ptr; 
    } 
} 

std::enabled_if<!std::is_destructible<T>::value, void>::type custom_delete(T* ptr) { 
    if (!m_lpfnCustomDeleter) { 
      throw "No custom deleter for a non destructible type!"; 
    } 
    m_lpfnCustomDeleter(ptr); 
} 

enabled_if Wille Machen Sie es so, dass die Funktion, wo es das Objekt direkt in Ihrer Liste nicht existiert, wenn das Objekt einen privaten Destruktor hat.

Alternativ können Sie eine Struktur (oder Funktion) übergeben, die als benutzerdefiniertes Löschelement als zweites Vorlagenargument Ihrer Liste mit einem Standardwert fungiert, der den Löschoperator aufruft, und diese Struktur dann direkt auf Ihrem Zeiger aufrufen in Arunmu's Anser.

Verwandte Themen