Как разрешить неконстантный конструктор копирования для временных - PullRequest
0 голосов
/ 12 января 2012

Как мне разрешить, чтобы класс с конструктором копирования, который принимает неконстантную ссылку, был создан из временных объектов для копирования?

Фон выглядит так:

У меня есть функция, которая должна возвращать список указателей на объекты, которые все наследуются от Base, поэтому мне нужно что-то вроде vector<Base*>. Учитывая, что vector<auto_ptr> не является чем-то особенным, я хотел написать простую оболочку вокруг vector<Base*>, которая удаляет все элементы в своем деструкторе.

Я столкнулся со следующей проблемой:

Мой класс имеет конструктор копирования следующим образом:

auto_list(auto_list& rhs);

чтобы я мог скопировать список указателей в новый экземпляр и очистить его в старом.

Но очевидно, что это не будет работать с возвращаемыми значениями, потому что временные ссылки не привязываются к неконстантной ссылке. Видя, что auto_ptr можно вернуть из функций, как они это реализовали?

Примечание: я не могу использовать C ++ 11 или boost, поэтому семантика перемещения или unique_ptr не являются опцией.

Если это поможет, это мой код:

template <typename T> class auto_list
{
private:

    vector<T*> pointers;

public:

    auto_list(vector<T*>& pointers)
    {
        this->pointers = pointers;
    }

    auto_list(auto_list& rhs)
    {
        this->pointers = rhs.pointers;
        rhs.pointers.clear();
    }

    ~auto_list()
    {
        for(typename vector<T*>::const_iterator it = this->pointers.begin(); it != this->pointers.end(); it++)
        {
            delete (*it);
        }
    }

    auto_list& operator=(auto_list& rhs)
    {
        this->pointers = rhs.pointers;
        rhs.pointers.clear();
    }

    vector<T*> get_pointers() const
    {
        return this->pointers;
    }
};

Ответы [ 4 ]

3 голосов
/ 12 января 2012

Этот класс будет довольно запутанным, как и сам auto_ptr, и я призываю вас использовать более разумные умные указатели. Даже если у вас есть веская причина не использовать Boost (и я не думаю, почему нет), как насчет std::tr1::shared_ptr?

Если вы полны решимости продолжить этот курс, тогда auto_ptr решает проблему инициализации из временного объекта, заключая ссылку в класс (auto_ptr_ref). Оболочка создается функцией преобразования из *this (которая является lvalue и поэтому может быть связана с неконстантной ссылкой), а затем может быть передана по значению в конструктор.

Вы можете сделать что-то похожее:

template <typename T> class auto_list_ref
{
    friend class auto_list<T>;
    auto_list_ref(auto_list<T> & ref) : ref(ref) {}
    auto_list<T> & ref;
};

template <typename T> class auto_list
{
public:
    // Add a constructor and conversion operator as follows:

    auto_list(auto_list_ref<T> rhs)
    {
        this->pointers = rhs.ref.pointers;
        rhs.ref.pointers.clear();
    }

    operator auto_list_ref<T>() {return auto_list_ref<T>(*this);}
};

Вот демонстрация.

2 голосов
/ 12 января 2012

Причина, по которой были созданы ссылки на rvalue, заключалась в том, что это не может работать в C ++ 03.Я имею в виду, по сути, совершенно, сломлен.Вы пытаетесь бороться с чем-то, что не может быть сделано.Придерживайтесь передачи возвращаемых значений или указателей, выделенных в куче.

1 голос
/ 12 января 2012

Вы можете объявить pointers как mutable, что позволит вам объявить ваши копии ctor и операции присваивания как принимающие const auto_list & и все еще вызывать очистку. Однако вам нужно осторожно использовать полученный класс, так как любая копия удалит скопированный объект.

0 голосов
/ 12 января 2012

Если вы просто работаете над отсутствием std::vector<auto_ptr<Base>> с вашим auto_list, я советую полностью исключить класс и написать свои собственные подсчитанные указатели, которые работают с std::vector.Если все, что вам нужно, это хранить общие объекты Base, вы даже можете сделать так, чтобы подсчет ссылок был таким, что код будет меньше, чем пользовательский список, который вы сейчас пишете.

Если это не сработает, вашВторой лучший выбор, вероятно, заключается в том, чтобы принять неработающий стандарт, обработанный unique_ptr<> до C ++ 11.Т.е. передать const reference и сделать const_cast (чёрт !!!).Если вы решите это, будьте очень, очень, очень осторожны, чтобы все время правильно понимать семантику (они будут достаточно нарушены константными вещами, не являющимися константами).

...