3 Stimmen

Intelligente Referenzen in C++

Edit: Tja, das war wohl eine schreckliche Idee.

Ist es möglich, einen intelligenten Verweis in C++ (für eine bestimmte Klasse, da Sie den Operator . nicht überladen können) mit der gleichen Semantik wie eine normale C++-Referenz zu machen, aber das ist reseated, wenn in einem STL-Container verwendet?

Zum Beispiel, wenn ich einige int_ref Klasse mit den normalen Ganzzahloperatoren überladen, und Konstruktion und Zuweisung sehen wie folgt aus:

class int_ref{
    int * p;
public:
    int_ref(int * ip) : p(ip) {}
    int_ref(const int_ref & other) : p(other.p) { 
        /* maybe some refcounting stuff here */ 
    }
    int_ref & operator = (const int_ref & other){
        if (!p) 
            throw something_bad();
        *p = *other.p;
        return *this;
    }
    void reseat(const int_ref & other){
        p = other.p;
    }
}

Dann kann ich das nicht mit std::vector da die Referenzen nicht wiederhergestellt werden, und das möchte ich nicht:

std::vector<int_ref> vec;
int_ref five = new int(5);
vec.push_back(five);
vec.push_back(new int(1));
std::sort(vec.begin(), vec.end()); // the value of five is now 1

Ich kann rvalue-Referenzen verwenden, damit es mit der STL zusammenpasst,

int_ref & operator=(int_ref && other){
    reseat(other);
    return *this;
}

Aber dann wird eine Funktion, die eine int_ref würde die rvalue-Überladung verwenden, und ich würde dies erhalten:

int_ref make_number(){
    return new int(10);
}

int_ref ref = new int(5);
int_ref other = ref;
other = make_number();    // instead of copying, as a reference would,
                          // other now points to something other than ref

Gibt es eine Möglichkeit, dies zu umgehen? Ist das generell eine schreckliche Idee?

4voto

Steve Jessop Punkte 264569

Ein Problem bei dem Versuch, dies zu tun, ist operator& . Bei einem Verweis wird die Adresse des Verweises angegeben (da Verweise keine Adresse haben). Bei einem Element eines Containers wird jedoch erwartet, dass es die Adresse des Elements angibt (da diese eine Adresse haben).

Ein Element eines Containers kann also in dieser Hinsicht keine Referenzsemantik nachahmen. Wenn Sie überladen operator& die Adresse des Verweisers zurückgeben, dann ist zum Beispiel die Garantie für zusammenhängende Speicherung von vector wird verletzt, da es heißt &v[n] == &v[0] + n für alle 0 <= n < v.size()

boost::addressof() wurde erfunden, um dieses Problem zu umgehen, so dass Sie nicht mit & um die Adresse eines Objekts in generischem Code zu erhalten. Aber selbst der Standard ist zu faul zu sagen static_cast<T*>(&static_cast<char&>(v[n])) statt &v[n] . Selbst wenn Sie daran denken, es zu verwenden, ist es ziemlich schwierig zu entscheiden, wann Sie die tatsächliche Adresse des Objekts wollen und wann Sie die Adresse wollen, von der der Autor des Objekts denkt, dass Sie sie wollen. Am besten ist es, unary nie zu überladen operator& . Das bedeutet, dass Sie eine partielle Version der Referenzsemantik erhalten, die auf ihre eigene Art und Weise verwirrend sein kann.

3voto

Martin York Punkte 245363

Was Sie wahrscheinlich verwenden möchten, ist ein boost:ptr_{container}.

Sie speichern Zeiger im Container (und der Container übernimmt das Eigentum). Beim Zugriff auf das Objekt erhalten Sie jedoch Verweise auf das Objekt und nicht auf den Zeiger.

#include <boost/ptr_container/ptr_vector.hpp>

int main()
{
     boost::ptr_vector<int>    data;
     data.push_back(new int(5));

     std::cout << data[0] << "\n";  // Prints 5 as you get a reference to the object.
}

Oder wenn Sie nur Referenzen wünschen. Dann können Sie boost:ref verwenden

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X