unique_ptr эквивалент повышения?

Есть ли какой-нибудь эквивалентный класс для C ++ 1x std :: unique_ptr в библиотеках boost? Поведение, которое я ищу, - это возможность иметь заводскую функцию, безопасную для исключений, например, так ...

std::unique_ptr<Base> create_base()
{
    return std::unique_ptr<Base>(new Derived);
}

void some_other_function()
{
    std::unique_ptr<Base> b = create_base();

    // Do some stuff with b that may or may not throw an exception...

    // Now b is destructed automagically.
}

РЕДАКТИРОВАТЬ: Прямо сейчас я использую этот хак, который кажется лучшим, что я могу получить на данный момент ...

Base* create_base()
{
    return new Derived;
}

void some_other_function()
{
    boost::scoped_ptr<Base> b = create_base();

    // Do some stuff with b that may or may not throw an exception...

    // Now b is deleted automagically.
}

person Clark Gaebel    schedule 01.06.2010    source источник
comment
Кроме того, можно ли создать этот эффект, заставив конструктор копирования иметь семантику перемещения, а затем деструктор проверяет перед освобождением?   -  person Clark Gaebel    schedule 02.06.2010


Ответы (5)


Невозможно создать что-то вроде unique_ptr без C ++ 0x (где он является частью стандартной библиотеки, и поэтому Boost не должен его предоставлять).

В частности, без ссылок на rvalue, которые являются особенностью C ++ 0x, надежная реализация unique_ptr невозможна, с Boost или без него.

В C ++ 03 есть несколько возможных альтернатив, но у каждой есть свои недостатки.

  • boost::shared_ptr - наверное, самая простая замена с точки зрения возможностей. Вы можете безопасно использовать его везде, где в противном случае использовали бы unique_ptr, и он сработает. Это было бы не так эффективно из-за добавленного подсчета ссылок. Но если вы ищете простую замену, способную справиться со всем, что unique_ptr может сделать, это, вероятно, ваш лучший выбор. (Конечно, shared_ptr также может делать намного больше, но его также можно просто использовать как замену unique_ptr.)
  • boost::scoped_ptr похож на unique_ptr, но не допускает передачу права собственности. Он отлично работает до тех пор, пока интеллектуальный указатель должен сохранять исключительное право собственности на протяжении всего срока службы.
  • std::auto_ptr работает очень похоже на unique_ptr, но имеет несколько ограничений, в основном то, что он не может храниться в контейнерах стандартной библиотеки. Если вы просто ищете указатель, который позволяет передавать право собственности, но который не предназначен для хранения в контейнерах или копирования, это, вероятно, хорошая ставка.
person jalf    schedule 01.06.2010
comment
+1 для auto_ptr - поскольку unique_ptr не будет компилироваться в мест, где auto_ptr вызывает ошибки, это именно то, что ищет OP. - person BlueRaja - Danny Pflughoeft; 02.06.2010
comment
Уникальный_ptr Говарда Хиннанта для c ++ 03 работает довольно хорошо, учитывая, что ссылок на r-значение не существует. - person deft_code; 02.06.2010
comment
Это не совсем так, как продемонстрировал Ховард Хиннант, используя эмуляцию семантики своего перемещения, которая уже была рассмотрена на Boost. Я надеюсь, что кто-то скоро возьмется за его реализацию и включит в Boost. - person Vicente Botet Escriba; 03.06.2010
comment
Он описывает это как захват большей части поведения реального unique_ptr, но, похоже, не описывает точно, каковы ограничения. Кто-нибудь знает? Я никогда не использовал его, но похоже, что вы правы, (большая часть) unique_ptr может быть реализована на C ++ 03. - person jalf; 08.02.2011
comment
boost :: scoped_ptr - плохая альтернатива, потому что он не работает с классами, объявленными вперед. boost :: shared_ptr - плохая альтернатива, потому что имеет значительные накладные расходы. - person Gabriel Schreiber; 28.02.2012
comment
@GabrielSchreiber: не работает с заранее объявленными классами? Как же так? Всегда отлично работал у меня - person jalf; 28.02.2012
comment
@jalf: Тестировал. Имеет отношение к boost :: checked_delete, вызываемой дескрутором scoped_ptr. Если вы явно определяете деструктор (класса, объединяющего scoped_ptr) и определение класса, содержащегося в scoped_ptr, видно там, все в порядке. Если вы полагаетесь на деструктор по умолчанию и определяете указанный класс в исходном файле, определение не отображается, когда конструктор по умолчанию создается компилятором (компилирует другой исходный файл) и не компилируется. - person Gabriel Schreiber; 28.02.2012
comment
@jalf: Но спасибо. До того, как я провел дополнительное тестирование, я думал, что это вообще невозможно, и теперь я знаю, как исправить свой код. - person Gabriel Schreiber; 28.02.2012
comment
да, это немного неудобно, и сообщения об ошибках, если вы ошиблись, не совсем полезны, но это выполнимо. :) Тем не менее, вы правы, что у всех альтернатив есть недостатки. Вот почему, в конце концов, был добавлен unique_ptr. :) - person jalf; 28.02.2012
comment
Еще одним недостатком boost::scoped_ptr является то, что он не предоставляет средства удаления клиентов. - person jamesdlin; 07.06.2013
comment
На данный момент этот ответ больше не является недействительным. См. мой ответ, в котором описывается boost::movelib::unique_ptr, представленный в Boost 1.57. - person Adam Romanek; 04.02.2015

Начиная с Boost 1.57 есть официальный unique_ptr реализация в библиотеке Boost.Move.

Из документации:

(...) замена std :: unique_ptr, которую можно использовать также из компиляторов C ++ 03.

Код доступен в <boost/move/unique_ptr.hpp> заголовочном файле и находится в пространстве имен boost::movelib. Более того, библиотека Boost.Move предоставляет make_unique() фабричную функцию в <boost/move/make_unique.hpp>, а также в boost::movelib пространстве имен.

Следовательно, пример из вопроса может быть реализован следующим образом:

#include <boost/move/unique_ptr.hpp>

using boost::movelib::unique_ptr;

unique_ptr<Base> create_base()
{
    return unique_ptr<Base>(new Derived);
}

См. живой пример на Wandbox. Обратите внимание, что код отлично компилируется с gcc 4.6.4 в режиме C ++ 98 (!).

Что интересно в boost::movelib::unique_ptr применительно к вашему случаю с базовыми / производными классами, реализация обеспечивает проверку во время компиляции объявления виртуального деструктора в базовом классе. Если вы его пропустите, код не будет компилироваться (нажмите кнопку «Выполнить (...)», чтобы увидеть сообщение об ошибке компилятора).

Одна небольшая проблема заключается в том, что включения происходят из каталога boost/move, но код находится в пространстве имен boost::movelib (небольшая разница, но может раздражать).

См. Также ветку о повышении список рассылки для получения более подробной информации.

Спасибо Иону Газтаньяге за этот абсолютно уникальный и полезный фрагмент кода.

person Adam Romanek    schedule 28.01.2015

Возможно, вы захотите попробовать реализацию «доказательства концепции» unique_ptr<> Говарда Хиннанта для C ++ 03 (отказ от ответственности - у меня нет):

Один из его примеров возвращает unique_ptr<int>:

unique_ptr<int> factory(int i)
{
    return unique_ptr<int>(new int(i));
}
person Michael Burr    schedule 01.06.2010
comment
Я использовал это в производственном коде, он работает очень хорошо. Единственная проблема, с которой мы столкнулись, - это вызов boost::make_shared для class с параметром unique_ptr. - person deft_code; 02.06.2010

Как насчет _1 _ из библиотеки interprocess?

person fbrereto    schedule 01.06.2010
comment
Можно ли безопасно вернуть это из функции? Я ничего не мог найти об этом (но, может быть, я просто слепой). Кроме того, правильно ли это использовать, учитывая, что он находится в межпроцессной библиотеке, а не в библиотеке интеллектуальных указателей? - person Clark Gaebel; 02.06.2010
comment
@wowus: Нет. Это полагается на семантику перемещения, которая является новой в C ++ 0x. Это нельзя просто эмулировать с помощью boost - эта функция должна существовать в самом компиляторе. - person Billy ONeal; 02.06.2010
comment
Только что посмотрел, нужны ссылки на r-значение. Следовательно, это не то, что я ищу. - person Clark Gaebel; 02.06.2010
comment
Interprocess unique_ptr имеет собственную эмуляцию хода для C ++ 03, то же самое, что и Boost.Move, если я не ошибаюсь. - person Vicente Botet Escriba; 03.06.2010
comment
@Clark Gaebel, как указано Винсенте в комментарии выше, да, unique_ptr из Boost.Interprocess может быть безопасно возвращен из функции через boost::move(). Я использую unique_ptr из Boost.Interprocess примерно два года с большим успехом. - person Adam Romanek; 28.01.2015

Я использовал unique_ptr Ховарда Хиннанта. Если вы не очень хорошо умеете читать сумасшедшие ошибки метапрограммирования из вашего компилятора, возможно, вам стоит держаться подальше. Однако в 90% случаев он действует так же, как unique_ptr.

В противном случае я бы предложил передать параметры как boost::scoped_ptr& и поменять местами внутри, чтобы украсть право собственности. Чтобы получить возвращаемые значения стиля unique_ptr, используйте auto_ptr. Сохраните возвращаемое значение auto_ptr в shared_ptr или scoped_ptr, чтобы не использовать auto_ptr напрямую.

person deft_code    schedule 02.06.2010