Я изучаю Правило нуля и есть 2 вопроса для последнего фрагмента кода, который демонстрирует правило.
class module {
public:
explicit module(std::wstring const& name)
: handle { ::LoadLibrary(name.c_str()), &::FreeLibrary } {}
// other module related functions go here
private:
using module_handle = std::unique_ptr<void, decltype(&::FreeLibrary)>;
module_handle handle;
};
Зачем использовать фигурные скобки вместо скобок для инициализации дескриптора?
Это равномерная инициализация метод введен в C ++ 11
Что делает с помощью module_handle = std :: unique_ptr; значит именно в этом контексте? Можно ли заменить его typedef?
Это наложение шаблона а также для создания нового типа. using
это новая и мощная замена typedef
explicit module(std::wstring const& name)
: handle { ::LoadLibrary(name.c_str()), &::FreeLibrary }
1) Это новый (унифицированный) синтаксис списка инициализаторов для C ++ 11. Он передает 2 аргумента функции конструкции, которая инициализирует переменную handle
, В этом случае он фактически такой же, как
explicit module(std::wstring const& name)
: handle(::LoadLibrary(name.c_str()), &::FreeLibrary)
Который назовет std::unique_ptr
конструктор, который принимает «указатель» (в данном случае дескриптор) и удалитель (адрес FreeLibrary
).
using module_handle = std::unique_ptr<void, decltype(&::FreeLibrary)>;
2) Это в основном то же самое, что и typedef. Для получения дополнительной информации см. этот.
- Зачем использовать фигурные скобки вместо скобок для инициализации дескриптора?
Другие сказали какие фигурные скобки — это (равномерная инициализация), но никто не объяснил, почему можно использовать его здесь, когда скобки должны работать так же хорошо.
Идея состоит в том, что вместо изучения всех различных синтаксисов инициализации C ++ 11 позволяет просто изучить один синтаксис и использовать его везде; Равномерная инициализация является одной из функций, добавленных с целью облегчить обучение написанию на C ++ (среди прочих причин).
Следует отметить, что равномерная инициализация является однородной в том смысле, что она работает во всех контекстах инициализации и может выполнять различные виды инициализации (например, агрегатная инициализация или использование конструктора), но это не означает, что любая инициализация может быть выполнена используй это; В частности, есть несколько угловых случаев, когда типы могут быть определены так, чтобы при одинаковой инициализации не было доступа к определенным конструкторам. Ответ на этот вопрос заключается в том, что просто не следует писать такие конструкторы. К сожалению, некоторые уже встроены в стандартную библиотеку, vector<int>(4, 5)
против vector<int>{4, 5}
быть распространенным примером.
2. Что делает с помощью module_handle = std :: unique_ptr; значит именно в этом контексте? Можно ли заменить его typedef?
Это просто другой синтаксис для typedef. Синтаксис является более мощным, чем typedef, потому что он может быть шаблонным, однако в этом случае он не используется. Этот пример может быть реализован с использованием typedef.
Причина, по которой предпочтение отдается новому синтаксису, заключается в том, что он является более ориентированным на тип, синтаксис типа C ++.
Старый синтаксис typedef использует (и страдает, по мнению многих) правило «объявления, имитирующего использование» C; То есть использование указателя выглядит *ptr
поэтому объявление указателя использует то же выражение, int *ptr;
, Использование функции, которая возвращает указатель на функцию, выглядит следующим образом (*foo())()
поэтому, объявляя снова одно и то же выражение, int (*foo())();
, Этот синтаксис ориентирован на выражения, где вы выписываете выражение, а язык выводит подразумеваемый тип переменной.
Проблема с этим синтаксисом состоит в том, что он смущает многих людей, и со временем и C, и C ++ были изменены различными способами, несовместимыми с этим первоначальным идеалом. Например, объявление функции в C изначально следовало этому правилу; В более ранних версиях C вы могли объявить функцию с int foo(x, y)
который точно имитирует выражение вызова функции foo(x, y)
, Позже стало ясно, что безопасность типов и проверка важны, и в ISO C объявление функции выглядит так: int foo(int x, int y)
, который не так близко имитирует использование функции.
C ++ пошел дальше, например, введя ссылки. Поскольку использование ссылок ничем не отличается от использования обычных объектов, нет синтаксиса, который можно было бы добавить к объявлению, следуя «использованию имитации объявления». Вместо этого они просто решили не следовать правилу и просто выбрали синтаксис, который не будет противоречить ему.
C ++ также уделяет гораздо больше внимания типам, чем C; шаблоны, которые параметризуются по типу, по типу перегрузки и т. д.
Таким образом, поскольку старый синтаксис кажется изначально проблематичным, а C ++ придает большее значение типам, а не выражениям, C ++ 11 вводит этот новый синтаксис для псевдонимов типов. Вместо неясного синтаксиса это просто using <type alias> = <type>;
, Нет необходимости в «спиральном правиле» или «справа налево».
Этот синтаксис не только может полностью заменить typedefs, но также добавляет возможность непосредственного создания шаблонов, заменяя старый typedef внутри хака шаблонного класса, который давно необходим. Опять же, новый синтаксис — это дополнительная функция, которая облегчает изучение C ++.