Умные ссылки в C ++ - PullRequest
       40

Умные ссылки в C ++

3 голосов
/ 17 сентября 2011

Edit: Welp, я думаю, это была ужасная идея.

Можно ли создать интеллектуальную ссылку в C ++ (для определенного класса, поскольку вы не можете перегрузить оператор.) С той же семантикой, что и обычная ссылка C ++, но которая повторно устанавливается при использовании в контейнере STL?

Например, если у меня есть какой-то класс int_ref с перегруженными обычными целочисленными операторами, а конструкция и присваивание выглядят так:

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

Тогда я не могу использовать это с std::vector, так как он не будет перезаписывать ссылки, и я не хочу такого рода вещи:

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

Я могу использовать rvalue-ссылки, чтобы он хорошо работал с STL,

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

Но тогда функция, которая возвращает int_ref, будет использовать перегрузку rvalue, и я получу это:

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

Есть ли способ обойти это? Это вообще ужасная идея?

Ответы [ 2 ]

4 голосов
/ 18 сентября 2011

Одна проблема даже с попыткой сделать это - operator&.Для справки, он дает вам адрес реферада (поскольку ссылки не имеют адреса).Для элемента контейнера, однако, ожидается, что он даст вам адрес элемента (поскольку у них есть адреса).

Таким образом, элемент контейнера не может имитировать ссылочную семантику в этом отношении.Если вы перегрузите operator&, чтобы вернуть адрес реферада, то, например, нарушается непрерывная гарантия хранения vector, поскольку в нем говорится, что &v[n] == &v[0] + n для всех 0 <= n < v.size()

boost::addressof() было изобретеночтобы обойти эту проблему, чтобы вам не приходилось использовать & для получения адреса объекта в общем коде.Но даже стандарт слишком ленив, чтобы сказать static_cast<T*>(&static_cast<char&>(v[n])), а не &v[n].Даже когда вы думаете об его использовании, довольно сложно решить, когда вам нужен фактический адрес объекта и когда вы хотите адрес, который, по мнению автора объекта, вы хотите.Лучше просто никогда не перегружать унарный operator&.Это означает, что вы получите частичную версию семантики ссылок, которая потенциально может сбить с толку.

3 голосов
/ 18 сентября 2011

То, что вы, вероятно, хотите использовать, это повышение: ptr_ {container}.

Вы храните указатели в контейнере (и контейнер становится владельцем). Но при доступе к объекту вы получаете ссылки на объект, а не указатель.

#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.
}

В качестве альтернативы, если вы просто хотите ссылки. Тогда вы можете использовать boost: ref

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...