Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Z(long long);






// но ни с чем другим

Z(long) = delete;

};

 

См. также:

· Раздел черновика стандарта С++???

  • [N1717==04-0157] (Francis Glassborow and Lois Goldthwaite: explicit class and default definitions (an early proposal).
  • Bjarne Stroustrup: Control of class defaults (a dead end).
  • [N2326==07-0186] Lawrence Crowl: Defaulted and Deleted Functions.
  • [N3174=100164] B. Stroustrup: To move or not to move. An analysis of problems related to generated copy and move operations. Approved.

 

Управление поведением по умолчанию: копирование и перемещение

По умолчанию класс содержит 5 операций:

· Оператор копирования

· Конструктор копирования

· Оператор перемещения (move assignment)

· Конструктор перемещения

· Деструктор

При объявлении одной из этих операций вы должны проанализировать их все, и определить явно (или указать компилятору использовать семантику по умолчанию) только те, которые вам действительно необходимы. Рассматривайте копирование, перемещение и уничтожение, как тесно связанные, а не отдельные операции, которые можно спокойно комбинировать друг с другом; вы можете использовать любые комбинации этих операций, но только некоторые из них будут иметь смысл семантически.

Если пользователь явно определил любую из операций: деструктор, операторы перемещения или копирования (объявил, определил, любо воспользовался ключевыми словами delete или default), то по умолчанию, операции перемещения сгенерированы не будут. Если же пользователь явно определил любую из операций: операторы перемещения, копирования или деструктор (объявил, определил, любо воспользовался ключевыми словами delete или default), то неоговоренные операции копирования будут определены автоматически с поведением по умолчанию. Однако такое поведение является устаревшим (deprecated), так что рассчитывать на него не стоит. Например:

class X1 {

X1& operator=(const X1&) = delete; // запрещаем копирование

};

 

Это также запрещает перемещение (moving) класса экземпляров X1. Конструктор копирования разрешен, но является устаревшим (deprecated).

class X2 {

X2& operator=(const X2&) = default;

};

 

Это объявление также явно запрещает перемещение экземпляров класса X2. Конструктор копирования разрешен, но является устаревшим (deprecated).

class X3 {

X3& operator=(X3& &) = delete; // Запрещаем перемещение

}

 

Это объявление также запрещает копирование экземпляров класса X3.

class X4 { ~X4() = delete; // Запрещаем деструктор }

 

Это объявление также запрещает перемещение объектов класса X4. Копирование разрешено, но является устаревшим.

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

template< class T> class Handle { T* p; public: Handle(T* pp): p{pp} {} // пользовательский деструктор: запрещается неявное копирование и перемещение ~Handle() { delete p; } // Передача владения Handle(Handle& & h): p{h.p} { h.p=nullptr; }; // Передача владения Handle& operator=(Handle& & h) { delete p; p=h.p; h.p=nullptr; } // Копирование запрещено Handle(const Handle&) = delete; Handle& operator=(const Handle&) = delete; //... };

 

См. также:

  • the C++ draft section???
  • [N2326==07-0186] Lawrence Crowl: Defaulted and Deleted Functions.
  • [N3174=100164] B. Stroustrup: To move or not to move. An analysis of problems related to generated copy and move operations. Approved.

 

enum class – строготипизированные перечисления с дополнительной областью видимости

enum class («новые перечисления» или «строгие перечисления» решает три проблемы обычных перечислений языка С++:

· Стандартные перечисления (enums) могут неявно преобразовываться к int, что может приводить к ошибкам, если кто-то не хочет, чтобы перечисления вели себя как целые числа.

· Стандартные перечисления экспортируют свои значения в окружающую (surrounding) область видимости (scope), что приводит к коллизиям имен.

· Невозможно указать тип, лежащий в основе стандартных перечислений (underlying type), что приводит к непониманию, проблемам совместимости и делает предварительное объявление (forward declaration) невозможным.

enum class («строгие перечисления) являются строготипизированными и с дополнительной областью видимости (scoped):

enum Alert { green, yellow, election, red }; // обычное перечисление // строготипизированное перечисление с дополнительной областью видимости // имена перечисления не экспортируются в окружающую область видимости // отсутствует неявное преобразования имен перечисления к int enum class Color { red, blue }; enum class TrafficLight { red, yellow, green }; Alert a = 7; // ошибка (как обычно C++) Color c = 7; // ошибка: нет преобразования int-> Color int a2 = red; // ОК: преобразование Alert-> int int a3 = Alert:: red; // ошибка в C++98; ОК в C++11 int a4 = blue; // ошибка: blue не объявлено в текущей области видимости int a5 = Color:: blue; // ошибка: нет преобразования Color-> int Color a6 = Color:: blue; // ОК

 

Как показано выше, стандартные перечисления работают как и раньше, помимо этого появилась возможность квалифицировать имя элемента перечисления именем самого перечисления (int a3 = Alert:: red; в примере выше).

Новые перечисления являются «классом перечисления» (enum class), поскольку они объединяют поведение обыкновенных перечислений (являются именованными значениями) с некоторыми возможностями классов (наличие области видимости и отсутствие преобразований).

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

enum class Color: char { red, blue }; // компактное представление

// типом по умолчанию являетсяint

enum class TrafficLight { red, yellow, green };

// А какой размер E?

// (вычисляется согласно старым правилам;

// т.е. зависит от реализации " implementation defined")

enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U };

// теперь мы можем задать размер явно

enum EE: unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U };

 

Это также позволяет предварительное объявление (forward declaration) перечислений:

enum class Color_code: char; // (предварительное) объявление void foobar(Color_code* p); // использование этого объявления //... enum class Color_code: char { red, yellow, green, blue }; // определение

 

Типом, лежащим в основе перечисления должен быть знаковый или беззнаковый целочисленный тип; по умолчанию, это int.

В стандартной библиотеке классы перечисления используются:

· Для отражения системных кодов ошибок: enum class errc;

· Для определения безопасности указателей (pointer safety): enum class pointer_safety { relaxed, preferred, strict };

· Для ошибок потоков ввода-вывода: enum class io_errc { stream = 1 };

· Для обработки ошибок при асинхронном взаимодействии: enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied };

Для некоторых из этих типов объявлены операторы, например оператор ==.

См. также:

  • the C++ draft section 7.2
  • [N1513=03-0096] David E. Miller: Improving Enumeration Types (original enum proposal).
  • [N2347 = J16/07-0207] David E. Miller, Herb Sutter, and Bjarne Stroustrup: Strongly Typed Enums (revision 3).
  • [N2499=08-0009] Alberto Ganesh Barbati: Forward declaration of enumerations.

 

сonstexpr – обобщенные гарантировано константные выражения

Механизм constexpr

· Предоставляет более обобщенный механизм константных выражений

· Позволяет определять константные выражения, используя типы, определенные пользователем

· Гарантирует инициализацию выражений во время компиляции

Давайте рассмотрим следующий пример:

enum Flags { good=0, fail=1, bad=2, eof=4 }; constexpr int operator|(Flags f1, Flags f2) { return Flags(int(f1)|int(f2)); } void f(Flags x) { switch (x) { case bad: /*... */ break; case eof: /*... */ break; case bad|eof: /*... */ break; default: /*... */ break; } }

 

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

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

constexpr int x1 = bad|eof; // ОК void f(Flags f3) { // ошибка: невозможно вычислить выражение во время компиляции constexpr int x2 = bad|f3; int x3 = bad|f3; // ОК }

 

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

Этот механизм также работает для объектов с достаточно простыми конструкторами и для выражений с этими объектами.

struct Point { int x, y; constexpr Point(int xx, int yy): x(xx), y(yy) { } }; constexpr Point origo(0, 0); constexpr int z = origo.x; constexpr Point a[] = {Point(0, 0), Point(1, 1), Point(2, 2) }; constexpr int x = a[1].x; // x равняется 1

 

Обратите, пожалуйста, внимание, что constexpr не является механизмом общего назначения для замены ключевого слова const (и наоборот):

· Основное назначение ключевого слова const заключается в выражении того, что объект не может быть изменен через его интерфейс (хотя объект может быть спокойно изменен через другие интерфейсы). Просто так уж получается, что объявление объекта константным дает отличные возможности компилятору для оптимизации. В частности, если объект объявлен с ключевым словом const и его адрес не вычисляется, компилятор обычно может выполнить его инициализацию во время компиляции (хотя это и не гарантируется) и хранить этот объект в собственных таблицах вместо помещения его в сгенерированный код.

· Основное назначение ключевого слова constexpr заключается в расширении диапазона того, что может быть вычислено во время компиляции, делая эти вычисления типобезопасными. Инициализаторы объектов, объявленные с ключевым словом constexpr, выполняются на этапе компиляции; по сути - это значения, которые хранятся в таблицах компилятора и они попадают в сгенерированный код только при необходимости.

См. также:

  • the C++ draft 3.6.2 Initialization of non-local objects, 3.9 Types [12], 5.19 Constant expressions, 7.1.5 The constexpr specifier
  • [N1521=03-0104] Gabriel Dos Reis: Generalized Constant Expressions (original proposal).
  • [N2235=07-0095] Gabriel Dos Reis, Bjarne Stroustrup, and Jens Maurer: Generalized Constant Expressions -- Revision 5.

 

decltype – тип выражения

decltype(E) – это тип («объявленный тип», declared type) имени или выражения E, который может быть использован в объявлениях. Например:

void f(const vector< int> & a, vector< float> & b) { typedef decltype(a[0]*b[0]) Tmp; for (int i=0; i< b.size(); ++i) { Tmp* p = new Tmp(a[i]*b[i]); //... } //... }

 

Эта идея, под названием “typeof” была уже давно известна в среде обобщенного (generic) программирования, но реальные реализации typeof всегда были неполными и несовместимыми, поэтому в текущем стандарте было решено использовать новое понятие: decltype.

Если вам просто нужен тип переменной, которую вы хотите проинициализировать, то более простым решением является использование ключевого слова auto. Использование decltype может понадобиться для чего-то другого помимо типа переменных, например, для типов возвращаемого значения.

См. также:

  • the C++ draft 7.1.6.2 Simple type specifiers
  • [Str02] Bjarne Stroustrup. Draft proposal for " typeof". C++ reflector message c++std-ext-5364, October 2002. (original suggestion).
  • [N1478=03-0061] Jaakko Jarvi, Bjarne Stroustrup, Douglas Gregor, and Jeremy Siek: Decltype and auto (original proposal).
  • [N2343=07-0203] Jaakko Jarvi, Bjarne Stroustrup, and Gabriel Dos Reis: Decltype (revision 7): proposed wording.

 






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.