Вызывает ли использование членов данных std :: auto_ptr UB? - PullRequest
0 голосов
/ 23 ноября 2010

В качестве продолжения к Классу, содержащему auto_ptr, хранящемуся в векторе , я полагаю, что неустановленный вывод состоит в том, что можно использовать классы с элементом auto_ptr в качестве элементов контейнера, если конструкция копирования и назначение копирования определяются пользователем (чтобы не вызывать конструктор копирования auto_ptr s и назначение копирования). что-нибудь в этом нарушает требования Стандартной библиотеки?

Пожалуйста, скажите мне, если что-то не так с этим, поскольку я хотел бы начать делать это идиоматически:

#include <memory>
#include <algorithm>

class Y { /* ... */ };
class Z : public Y { /* ... */ };

class X {
    public:
        X() : ap(new Z()) {}
        X(const X& other) : ap(other.ap->clone()) {}
        X& operator=(X other) { swap(other); return *this; } // any problem with swap?
        void swap(X& other) { std::swap(ap, other.ap); }
        // note no destructor necessary
    private:
        std::auto_ptr<Y> ap; // Y provides clone()
};

Обратите внимание, что я понял одну вещь: при таком подходе определение класса Y должно находиться в области видимости для определения X (в отличие от просто объявленного вперед, когда "необработанный" указатель на Y используется). Это происходит потому, что когда создается экземпляр auto_ptr, его деструктор должен вызвать delete для Y, и поэтому Y не может быть неполным типом. Я полагаю, что это должно быть сопоставлено со значением RAII в случае, если класс X управлял несколькими ресурсами (имеет несколько auto_ptr членов). Есть мысли по этому поводу?

Я думаю, что этот метод в целом хорош, чтобы исключить много хитрого кода для классов, которым, возможно, придется создать / уничтожить / скопировать потенциально несколько ресурсов (принципал единой ответственности). Мне просто интересно, служит ли auto_ptr для этой цели или не работает здесь из-за какого-то тонкого языка / требований Стандартной библиотеки.

Обратите внимание, что мне известны другие типы интеллектуальных указателей, но я реализую интерфейс библиотеки и не хочу навязывать какие-либо требования для Boost или TR1 для моих клиентов. Любая лекция по использованию auto_ptr в целом будет отклонена!

Ответы [ 3 ]

1 голос
/ 23 ноября 2010

Использование auto_ptr, когда деструктор находится вне области действия , вызывает , вызывает неопределенное поведение. MSVC предупреждает об этом. GCC нет.

Вы можете заставить его работать, но только если деструктор не определен как встроенная функция.

Unique_ptr и scoped_ptr решают эту проблему. По крайней мере, с теми, кто не может написать неопределенный код случайно.

1 голос
/ 23 ноября 2010

Я думаю, что вы реализовали клонирование интеллектуального указателя поверх std::auto_ptr. Я не уверен, что это стоит хлопот, так как вы не очень далеки от реализации одного поверх тупого указателя.

Но, насколько я понимаю, в этом нет ошибки. (Конечно, если вы скажете так, кто-то укажет на очевидный недостаток через 5 минут после того, как я опубликую это ...)

0 голосов
/ 23 ноября 2010

Что вы действительно пытаетесь сделать?Похоже, много ненужной работы, если вы просто хотите иметь кучу объектов в контейнере.создание временного объекта и получение объекта в контейнере с правами собственности не является проблемой в моем мышлении

operator =() не имеет смысла для меня, это не так = это обмен.

X a,b;
a=b
assert(a==b) // fail!

Ваша реализация неверна

Обратите внимание, что я понял, что при таком подходе определение класса Y должно находиться в области действия определения X (в отличие от просто объявленного заранее).когда используется «сырой» указатель на Y).Это происходит потому, что когда создается экземпляр auto_ptr, его деструктор должен вызывать delete для Y, и поэтому Y не может быть неполным типом.

, если вы определяете деструктор для X и внедряете его в файл CPP,вполне законно можно сделать

header

class Y;
class X{
  virtual ~X();
  std::auto_ptr<Y> ap; 
};

body

class Y{};
~X(){}
...