Spec-Zone.ru › C++

Инициализация копированием

Инициализирует объект из другого объекта.

Синтаксис

T object = other; (1)
T object = {other}; (2) (до C++11)
f(other) (3)
return other; (4)
throw object;

catch (T object)

(5)
T array[N] = {other-sequence}; (6)

Объяснение

Инициализация копированием выполняется в следующих ситуациях:

1) Когда именованная переменная (автоматическая, статическая или локальная для потока) не ссылочного типа T объявляется с инициализатором, состоящим из знака равенства, за которым следует выражение.
2) (до C++11) Когда именованная переменная скалярного типа T объявляется с инициализатором, состоящим из знака равенства, за которым следует выражение в фигурных скобках (Примечание: начиная с C++11, это классифицируется как инициализация списком, и сужение типа не допускается).
3) При передаче аргумента функции по значению.
4) При возвращении из функции, возвращающей по значению.
5) При бросании или перехвате исключения по значению.
6) В рамках инициализации агрегатов, чтобы инициализировать каждый элемент, для которого указан инициализатор.

Эффекты инициализации копированием:

  • Сначала, если T — тип класса, а инициализатор — выражение prvalue, тип которого без квалификаторов cv совпадает с типом T, используется само выражение инициализатора, а не временный объект, созданный из него, для инициализации целевого объекта: см. исключение копирования.
(с C++17)
  • В противном случае, если T — тип класса, а тип other без квалификаторов cv — T или класс, производный от T, рассматриваются неявные конструкторы T и выбирается наиболее подходящий по принципу разрешения перегрузки. Затем вызывается этот конструктор для инициализации объекта.
  • В противном случае, если T — тип класса, а тип other без квалификаторов cv не T или не производный от T, или если T — не тип класса, но тип other — тип класса, рассматриваются пользовательские последовательности преобразований, которые могут преобразовать тип other в T (или в тип, производный от T, если T — тип класса и доступна функция преобразования) и выбирается лучшая из них по принципу разрешения перегрузки. Результат преобразования, который является временным объектом-выражением-справа(до C++11)временным объектом-выражением-справа(с C++11)(до C++17)выражением-справа(с C++17) типа T без квалификаторов cv, если использовался конструктор преобразования, затем используется для прямой инициализации объекта. Обычно последний шаг оптимизируется, и результат преобразования создается непосредственно в памяти, выделенной для целевого объекта, но необходим доступный конструктор (перемещения или копирования), хотя он и не используется.(до C++17)
  • В противном случае (если ни T, ни тип other не являются типами классов), при необходимости используются стандартные преобразования для преобразования значения other в тип T без квалификаторов cv.

Примечания

Инициализация копированием менее гибкая, чем прямая инициализация: явные конструкторы не являются конструкторами преобразования и не рассматриваются при инициализации копированием.

struct Exp { explicit Exp(const char*) {} }; // not convertible from const char*
Exp e1("abc");  // OK
Exp e2 = "abc"; // Error, copy-initialization does not consider explicit constructor
 
struct Imp { Imp(const char*) {} }; // convertible from const char*
Imp i1("abc");  // OK
Imp i2 = "abc"; // OK

Кроме того, неявное преобразование при инициализации копированием должно генерировать T непосредственно из инициализатора, в то время как, например, прямая инициализация ожидает неявное преобразование из инициализатора в аргумент конструктора T.

struct S { S(std::string) {} }; // implicitly convertible from std::string
S s("abc");   // OK: conversion from const char[4] to std::string
S s = "abc";  // Error: no conversion from const char[4] to S
S s = "abc"s; // OK: conversion from std::string to S

Если other — выражение-справа, при разрешении перегрузки будет выбран конструктор перемещения и вызван во время инициализации копированием. Это все еще считается инициализацией копированием; нет специального термина (например, инициализация перемещением) для этого случая.

Неявное преобразование определяется в терминах инициализации копированием: если объект типа T может быть инициализирован копированием с помощью выражения E, то E неявно преобразуется в T.

Знак равенства, =, при инициализации копированием именованной переменной не связан с оператором присваивания. Перегрузки оператора присваивания не влияют на инициализацию копированием.

Пример

#include <memory>
#include <string>
#include <utility>
 
struct A
{
    operator int() { return 12;}
};
 
struct B
{
    B(int) {}
};
 
int main()
{
    std::string s = "test";        // OK: constructor is non-explicit
    std::string s2 = std::move(s); // this copy-initialization performs a move
 
//  std::unique_ptr<int> p = new int(1); // error: constructor is explicit
    std::unique_ptr<int> p(new int(1));  // OK: direct-initialization
 
    int n = 3.14;    // floating-integral conversion
    const int b = n; // const doesn't matter
    int c = b;       // ...either way
 
    A a;
    B b0 = 12;
//  B b1 = a;       // < error: conversion from 'A' to non-scalar type 'B' requested
    B b2{a};        // < identical, calling A::operator int(), then B::B(int)
    B b3 = {a};     // <
    auto b4 = B{a}; // <
 
//  b0 = a;         // < error, assignment operator overload needed
 
    [](...){}(c, b0, b3, b4); // pretend these variables are used
}

Отчеты об ошибках

Следующие отчеты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применён к Поведение, опубликованное Правильное поведение
CWG 5 C++98 квалификация cv целевого типа применяется к
временной переменной, инициализированной конструктором преобразования
временная переменная не имеет cv-квалификаций
CWG 177 C++98 категория значения временной переменной, созданной при
инициализации копированием объекта класса, не определена
определена как выражение-справа

См. также

  • исключение копирования
  • конструктор преобразования
  • копирующее присваивание
  • конструктор копирования
  • конструктор по умолчанию
  • деструктор
  • explicit
  • инициализация
    • инициализация агрегатов
    • инициализация констант
    • инициализация по умолчанию
    • прямая инициализация
    • список инициализаторов
    • инициализация списком
    • инициализация ссылок
    • инициализация значением
    • инициализация нулём
  • присваивание перемещением
  • конструктор перемещения
  • new

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/copy_initialization

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API