Невозможно вернуть элемент unique_ptr из массива по значению

Следующее компилируется и работает как положено:

std::unique_ptr<char> input_to_char_array()
{
    std::unique_ptr<char> c;
    c.reset(new char('b'));
    // c[1].reset(new char[20]());

    return c;
}

Но это не так:

std::unique_ptr<char> input_to_char_array()
{
    std::unique_ptr<char> c[2];
    c[0].reset(new char('b'));
    c[1].reset(new char('a'));

    return c[0]; // is this considered "return statement's expression is the name of a non-volatile object with automatic storage duration"
}

Вывод g++:error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = char; _Dp = std::default_delete<char>]

Из некоторых исследований SO Возврат unique_ptr из функций и Почему я не могу вернуть unique_ptr из пары? кажется, что это все, что связано с исключением копирования и оптимизацией именованного возвращаемого значения.

Кто-нибудь может подтвердить, верна ли моя догадка. Если да, то каковы именно критерии для copy elison, чтобы можно было применить NRVO?


person Rich    schedule 14.07.2015    source источник
comment
Это сказано в ответе на тот самый вопрос, на который вы ссылаетесь, не так ли? This elision of copy/move operations, called copy elision, is permitted [...] in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object with the same cv-unqualified type as the function return type   -  person Taekahn    schedule 14.07.2015
comment
@Taekahn не c[0] имя автоматического объекта?   -  person Rich    schedule 14.07.2015
comment
c[0] — это выражение, а не имя.   -  person Sneftel    schedule 14.07.2015
comment
запутался.. что такое имя? Идентификатор, обозначающий объект?   -  person Rich    schedule 14.07.2015
comment
Идея NRVO заключается в том, что ее можно реализовать в компиляторе, добавив в функцию дополнительный параметр. Этот параметр описывает ячейку памяти, в которой создается возвращаемое значение. В первом примере объект c будет создан непосредственно в этом месте, и оператор return станет неоперативным. Во втором примере невозможно построить возвращаемое значение в этом месте памяти, так как c больше (по размеру), чем возвращаемое значение.   -  person dyp    schedule 14.07.2015
comment
Но это не единственная причина, по которой он здесь не работает: NRVO изменяет наблюдаемое поведение, но не является обязательным, поэтому он был ограничен очень немногими случаями. Например, в первом кодовом блоке return *&c; предотвращает NRVO, несмотря на то, что функция имеет такое же поведение во всех остальных отношениях.   -  person dyp    schedule 14.07.2015
comment
@LokiAstari Возвращаемое значение обрабатывается как rvalue, если и только если копирование/перемещение может применяться (за вычетом некоторых послаблений). Итак, нам нужно определить, может ли применяться копирование/перемещение elision, тогда мы знаем, какой конструктор (копирование или перемещение) будет использоваться.   -  person dyp    schedule 14.07.2015
comment
@dyp: хорошо. Узнавайте что-то новое каждый день.   -  person Martin York    schedule 14.07.2015