Замена auto_ptr в VC++ 8

std::auto_ptr не работает в VC++ 8 (это то, что мы используем на работе). Моя главная претензия к этому заключается в том, что он позволяет auto_ptr<T> x = new T();, что, конечно, приводит к ужасным сбоям, хотя его легко сделать по ошибке.

Из ответа на еще один вопрос здесь, в stackoverflow:

Обратите внимание, что реализация std::auto_ptr в Visual Studio 2005 ужасно сломана. http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=98871 http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101842

я хочу использовать

  • boost::scoped_ptr для указателей, которые не должны передавать права собственности.
  • boost::shared_ptr для указателей в контейнерах и других местах, где они требуются.
  • std::auto_ptr для указателей, которые должны/могут передавать право собственности.

Но поскольку std::auto_ptr для меня не работает, мне интересно, какой подход будет лучшим:

  • Замените std::auto_ptr чем-нибудь из сети. Как этот это от Рани Шарони (еще не пробовал это еще).
  • Вместо этого используйте boost::shared_ptr. Конечно, будет работать, хотя будут небольшие накладные расходы, которые меня не волнуют. Но я хочу использовать auto_ptr, чтобы сигнализировать о намерении указателя. (См. этот ответ для голосования по этому подходу. .)
  • На практике мне никогда не понадобится передавать право собственности, поэтому мне не стоит об этом беспокоиться.

Обновление: вот что я сделал: я скопировал вышеупомянутую реализацию auto_ptr Рани Шарони. Отсюда.

Сделал небольшие тесты:

class T
{
public:
    T() {
        OutputDebugStringA("T\n");
    };
    ~T() {
        OutputDebugStringA("~T\n");
    };
};

{
    fix::auto_ptr<T> x(new T); // This just works.
}
{
    fix::auto_ptr<T> x = (new T); // Doesn't compile. Great!
}
{
    fix::auto_ptr<T> x = fix::auto_ptr<T>(new T); // Transfer of ownership works also.
}

Конечно, эти тесты ни в коем случае не являются исчерпывающими, и доверять им не стоит. Реализация шаблонного класса, безопасного для исключений, — дело непростое. По крайней мере, это работает лучше, чем встроенный.

Примечание: я не знаю, разрешено ли мне использовать эту реализацию в отношении авторских прав. Написал Рани, жду ответа. Я обновлю этот пост, когда узнаю больше. Разрешено всем использовать реализацию auto_ptr Рани Шарони по своему усмотрению.

Спасибо за все ваши ответы.


person Daniel Sönnerstedt    schedule 06.11.2008    source источник
comment
Передача права собственности происходит нечасто, но она обеспечивает удобный способ документирования себя как части кода.   -  person Martin York    schedule 07.11.2008
comment
Это именно моя мысль. Я обожаю самодокументирующийся код.   -  person Daniel Sönnerstedt    schedule 07.11.2008


Ответы (7)


Перейдите, чтобы повысить интеллектуальные указатели.

Тем временем вы можете извлечь работающую реализацию auto_ptr из старой/другой STL, чтобы у вас был рабочий код.

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

unique-ptr «исправляет» это, заставляя выпуск не только отказываться от права собственности, но и устанавливая для RHS значение null. Это самая близкая замена auto-ptr, но из-за другой семантики она не является заменой.

Есть вводная статья по ускорению интеллектуальных указателей, написанная, кхм, мной.

person peterchen    schedule 07.11.2008
comment
Я прочитал вашу статью. Это очень хорошо написано. Спасибо. В большинстве случаев указатели повышения будут в порядке. Я пока не уверен, как мне поступить с auto_ptr. Я пытаюсь установить новое руководство для интеллектуальных указателей на работе прямо сейчас, поэтому я лучше разберусь с этим. - person Daniel Sönnerstedt; 07.11.2008
comment
Э-э, auto_ptr также устанавливает нулевой RHS для любой копии. Вот как он отказывается от собственности! - person Pavel Minaev; 06.08.2009
comment
В некоторых (или первоначальных) реализациях IIRC этого не было. - person peterchen; 06.08.2009

Рассматривали ли вы возможность использования STLPort?

person OJ.    schedule 06.11.2008
comment
Это соответствовало бы идее «Заменить реализацию auto_ptr». Я надеюсь, что смогу сделать что-то меньшее, чем представить новую реализацию STL в нашем проекте. Ему два года, и мы, пятеро человек, пишем его. Но все равно спасибо. - person Daniel Sönnerstedt; 07.11.2008
comment
Технически замена вашей реализации STL не должна вызвать у вас никаких проблем. Если бы что-нибудь потом удалили. Но если у вас есть код, основанный на этих проблемах, то вы облажались. Учитывая, что это решение с перетаскиванием, возможно, стоит подумать, есть ли у вас пропускная способность для тестирования? - person OJ.; 07.11.2008
comment
Я поддерживаю это. Замена STL должна заключаться в простой настройке проекта для использования STLPort (который, как я полагаю, использует собственный STL, если он не сломан). - person Martin York; 07.11.2008
comment
Мне нужно выяснить, сколько работы потребуется для этого. Все только начиналось как попытка познакомить всех с умными указателями на работе. Затем у меня была ошибка доступа к памяти, к счастью, в наших модульных тестах. Нет, я должен убедить всех заменить их реализацию stl... - person Daniel Sönnerstedt; 07.11.2008

Используйте уникальный_ptr. Я думаю, что они были введены для улучшения auto_ptr.

http://www.boost.org/doc/libs/1_35_0/doc/html/interprocess/interprocess_smart_ptr.html#interprocess.interprocess_smart_ptr.unique_ptr

Фактически, я склонен полагать, что auto_ptr может быть объявлен устаревшим в пользу него:

http://objectmix.com/c/113487-std-auto_ptr-deprecated.html

person Scott Langham    schedule 06.11.2008
comment
У Boost есть один доступный, хотя я не уверен на 100%, какие версии VC имеют достаточное соответствие стандарту языка, чтобы поддерживать его. - person Scott Langham; 07.11.2008
comment
Кроме того, почему есть только boost::interprocess::unique_ptr и нет boost::unique_ptr. Я хотел бы узнать больше, прежде чем идти по этому пути. Стандартные предложения для unique_ptr, по-видимому, работают только с очень стандартными новыми компиляторами (gcc). - person Daniel Sönnerstedt; 07.11.2008
comment
Кроме того, я думаю, что отказ от auto_ptr будет актуален только после его замены на unique_ptr. - person Daniel Sönnerstedt; 07.11.2008
comment
Извините, да, я имел в виду, что в будущем это может быть устаревшим. Да, не уверен, почему есть только межпроцессная версия ... может быть, этот ответ сейчас не подходит, но, вероятно, станет актуальным в будущем. - person Scott Langham; 07.11.2008
comment
Boost обычно поддерживает все, начиная с VC7.1 (2003), хотя возможности некоторых библиотек могут быть ограничены. VC8 и выше обычно поддерживают все функции. - person Pavel Minaev; 06.08.2009

Как вы думаете, почему std::auto_ptr‹> не работает.

Я бы подумал, что о чем-то столь же плохом было бы сообщено в комитет по стандартам!

Вы имеете в виду, что вам нужно:

std::auto_ptr<T>   x(new T);  // Use the explicit constructor.
person Martin York    schedule 06.11.2008
comment
Не везде ломается. Только конкретно в VC++ 8. VC++ 9 имеет лучшую реализацию. - person Daniel Sönnerstedt; 07.11.2008
comment
да. Либо std::auto_ptr‹T› x(new T); или std::auto_ptr‹T› x = std::auto_ptr‹T›(новый T); буду работать. std::auto_ptr‹T› x = новый T; не должен компилироваться. Это происходит, и результат не определен. - person Daniel Sönnerstedt; 07.11.2008
comment
Что вы подразумеваете под «результаты не определены»? Разве он не должен просто неявно вызывать конструктор? Конечно, это все еще (возможно) недостаток. - person Konrad Rudolph; 07.11.2008
comment
Очень интересно. Я не слышал этого раньше. Можете ли вы добавить это к своему основному вопросу выше, чтобы он стал частью документации. - person Martin York; 07.11.2008
comment
Конрад Рудольф: Результаты не столько неопределенные, сколько сбой программы. Оператор auto_ptr= ожидает другого auto_ptr. Это была настоящая ошибка, с которой я имел дело сегодня. Мартин Йорк: Добавил дополнительную информацию к моему вопросу. - person Daniel Sönnerstedt; 07.11.2008

Используйте boost::shared_ptr/boost::scoped_ptr. Это будет предпочтительный смарт-указатель в будущих стандартах C++ (уже есть в TR1).

Изменить: найдите соответствующее обсуждение здесь: Идиоматическое использование std::auto_ptr или использовать только shared_ptr?

person MP24    schedule 06.11.2008
comment
Предпочтение - это сильно сказано. shared_ptr и auto_ptr делают разные вещи. - person Martin York; 07.11.2008
comment
Да, это правда: обычно я использую shared_ptr, но это может быть связано с тем, что у меня никогда не было вариантов использования auto_ptr. - person MP24; 07.11.2008
comment
Я уже слежу за другими дискуссиями об умных указателях здесь, в stackoverflow, но все равно спасибо. Я уже придерживаюсь мнения, что хотел бы использовать auto, shared и scoped. Но из-за моего компилятора (и его библиотечной реализации) я не знаю, что делать. - person Daniel Sönnerstedt; 07.11.2008

Насколько я помню, не было:

auto_ptr<T> x = auto_ptr<T>(new T()); ??
person Maciek    schedule 06.08.2009
comment
Это слишком длинно - auto_ptr<T> x(new T()) сделает то же самое менее окольным путем. - person Pavel Minaev; 06.08.2009

Не ответ, а для общего интереса всех, для кого эти баги актуальны. Существует еще одна связанная ошибка с auto_ptr в VC8, которая должна сделать с неявными upcasts. Это, вероятно, самое зло из всех, потому что другие ошибки просто позволяют вам без сбоев компилировать код, который в противном случае является незаконным в соответствии со стандартом, но, по крайней мере, совместимый код работает нормально. С этой ошибкой фактически совместимый код не работает должным образом.

Проблема вот в чем. Стандарт определяет конструкторы auto_ptr и операторы преобразования таким образом, чтобы они поддерживали неявное преобразование auto_ptr вверх, как и в случае с обычными указателями. Однако реализация этого в VC8 делает reinterpret_cast, а не static_cast. Естественно, не только это U.B. по букве стандарта, но он также нарушает множественные базовые классы и/или виртуальное наследование. Вот пример юридического кода, нарушенного этим:

struct Base1 { int x; };
struct Base2 { int y; };
struct Derived : Base1, Base2 {};

std::auto_ptr<Derived> createDerived()
{
  return std::auto_ptr<Derived>(new Derived);
}

std::auto_ptr<Base2> base2(createDerived());

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

person Pavel Minaev    schedule 06.08.2009