2016-09-26 3 views
17

В Herb Sutter's talk at CppCon16 он предложил написать идиому pimpl с const std::unique_ptr (примерно 10 минут).Использование const std :: unique_ptr для pimpl idiom

Как это должно работать с конструкторами/назначениями перемещения? Есть что-то в C++ 17? Я ничего не мог найти.

+0

Не прочитав разговор, очевидно, что классы с pimpl не могут быть скопированы/перемещены. Они будут создаваться в динамическом пространстве и доступны исключительно с помощью интеллектуальных указателей, причем pimpl скрывает внутренние детали реализации. –

+6

Почему вы не хотите, чтобы большинство ваших классов pimpl были перемещаемыми?Это кажется вполне разумным делом. –

+1

@ Денис Ярошевский может только предположить, что у него есть конкретный случай использования. В общем, я согласен с использованием 'unique_ptr'as контейнера для pimpl. Если вы хотите, чтобы его можно было копировать, вам нужно было бы реализовать это с точки зрения операции клонирования, конечно. –

ответ

2

Как это должно работать с конструкторами/назначениями перемещения?

Move constructors:

неявно объявленной или просроченный шаг конструктор для класса Т определяется как удаленные, если любое из следующих условий:

  • Т имеет не- статические элементы данных, которые не могут быть перемещены (удалены, недоступны или неоднозначные конструкторы перемещения)

const std::unique_ptr такой элемент данных из-за const.

Если const отбрасывается, компилятор генерирует конструктор перемещения и назначение, но не копирующие.


Herb объясняет, почему он использует const unique_ptr:

неконстантная может работать тоже, но это более хрупким, потому что перемещение по умолчанию семантика, вероятно, неправильно.

С const членом является более надежным, поскольку const члены должны быть инициализированы в конструкторе. И const документов, что реализация объекта не изменяется, это не шаблон состояния или стратегии.

+0

Тогда в таком случае нужно было бы реализовать конструктор копирования? – vordhosbn

+0

@ vordhosbn Если это необходимо. –

+0

Это правда, но мой вопрос касался перемещения/назначения перемещения. Использование plain unique_ptr вместо const будет продолжать движение/присвоение живым и хорошим ходом при объявлении его const запрещает его. Раньше я думал, что члены данных const являются плохой практикой (из-за этой проблемы), но, по-видимому, Herb Sutter не думает об этом. Я задавался вопросом, почему. –

8

Если ваш класс не должен быть пустым, непостоянный уникальный ptr (со стандартным перемещением/назначением) не подходит. Перемещение ctor и присваивание перемещения будут как пустыми.

Исключительный ptr отключит эти автоматические методы, и если вы хотите переместить, вам придется записать его внутри имплантата (и немного клея снаружи).

Я лично напишу значение ptr с семантикой, которую хочу (тогда пусть компилятор напишет клей), но начиная с const unique_ptr звучит разумно как первый проход.

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

Самая большая стоимость этой техники, трудности с возвратом значений, уходит с C++ 17.

+2

Если вы выйдете из объекта, то предположим, что он находится в частично сформированном состоянии, поэтому его можно назначить и уничтожить, поэтому перемещение конструктора/ассистента не нарушит вашу гарантию not_null. Вы можете придумать smth как not_null из gsl, чтобы обернуть его, если хотите. –

+0

@ Денис Ярошевский Нет, это в каком бы состоянии вы не хотели гарантировать? Он не «должен находиться в частично сформированном состоянии», если это не то, что вы * выбираете *, чтобы гарантировать. Один из вариантов состоит в том, чтобы быть почти-никогда-пустым и быть пустым только после перемещения. Это выбор, у него есть издержки и выгоды. Расходы на переход от никогда-пустых до почти никогда не пустых не должны быть уволены. То же самое стоит из-за того, что он почти никогда не бывает пустым и никогда не пустым. Никогда-пустое проще * гарантировать правильность *, и смещение в сторону более частого правильного кода по более быстрому коду часто является хорошей идеей. – Yakk

+0

@Yakk, даже если перемещенный объект «никогда не пуст», используя его после перемещения, является сильным запахом кода.Я бы сказал, что проверка указателя на pimpl, за которой следует assert/exception, предпочтительнее, чтобы люди зависели от перенесенного объекта, находящегося в состоянии «по умолчанию». Это вызывает катастрофу, когда гарантия больше не может быть выполнена из-за неизбежной ползучести миссии. Я бы зашел далеко, чтобы сказать, что это анти-шаблон, который противоречит духу 'std :: move'. –

Смежные вопросы