Класс с делегирующими конструкторами

class A {
  A(SomeObject obj,   // requires a new copy of the object 
    int x,
    const string& y
  ) { // additional logic }
  A(SomeObject obj, const string& y)   
    :A(obj, 0, y) {}     // will obj be copied?
};

Целевое использование:

SomeObject obj;
A a1(obj, "first");
A a2(obj, "second");

План состоит в том, чтобы построить SomeObject ровно один раз, когда выполняется построение A. Приведет ли передача obj к созданию копии другого SomeObject при делегировании другому конструктору? Если да, то как мне этого избежать?

c++
4
Candy Chiu 3 Янв 2018 в 01:52

2 ответа

Лучший ответ

Да, obj копируется при делегировании другому конструктору: это недопустимый контекст для copy elision или даже для автоматического перемещения.

Решение состоит в том, чтобы применить std::move к аргументу в списке инициализаторов членов или (для частный целевой конструктор) получает объект не по ссылке - const. Любой из них позволяет (общедоступному) конструктору по-прежнему получать свой аргумент по значению, как и рекомендация C ++ 11.

9
Davis Herring 2 Янв 2018 в 23:12

Нет. Он не копируется из одного конструктора в другой . Кажется, вы исходите из предположения, что один конструктор инициализирует объект, а затем передаст его другому, что не так. См. Эту цитату из стандарта:

Список-инициализатор-память может делегировать другому конструктору класса конструктора, используя любой тип class-or-decltype, который обозначает сам класс конструктора. Если mem-initializer-id обозначает класс конструктора, он должен быть единственным mem-инициализатором; конструктор - это делегирующий конструктор, а конструктор, выбранный mem-initializer, является целевым конструктором. Целевой конструктор выбирается по разрешению перегрузки. Как только целевой конструктор возвращается, тело делегирующего конструктора выполняется. Если конструктор делегирует самому себе прямо или косвенно, программа имеет неправильный формат, и диагностики не требуется.

Этот минимальный пример показывает, что Copied печатается только один раз:

#include <iostream>

struct Foo {
    Foo() = default;
    Foo(const Foo&) {
        std::cout << "Copied";
    }
};

struct A {
    A(Foo f, int i) { }
    A(Foo f) : A(f, 0) { }
};

int main() {
    A a{Foo{}};
}
-6
user9163035 2 Янв 2018 в 23:07