class A {
A();
A(const A&);
public:
A(int ) {}
};
A foo() {
return A(10);
}
int main() {
} //foo is never called!
Пример компилироваться не будет, потому что компилятор потребует копирующий конструктор, который недоступен. Но вот так подумать, зачем компилятору в этом случае копирующий конструктор? Какие промежуточные объекты создаютя в этом случае?
Здравствуйте, Vamp, Вы писали:
V>Вот простой пример: V>
V>class A {
V> A();
V> A(const A&);
V>public:
V> A(int ) {}
V>};
V>A foo() {
V> return A(10);
V>}
V>int main() {
V>} //foo is never called!
V>
V>Пример компилироваться не будет, потому что компилятор потребует копирующий конструктор, который недоступен. Но вот так подумать, зачем компилятору в этом случае копирующий конструктор? Какие промежуточные объекты создаютя в этом случае?
Ну как минимум он нужен в return — вернее сам процесс возвращения значения... еслибы была ссылка — всё бы было хорошо. читаем Трупа Страуса_
Здравствуйте, Vamp, Вы писали:
V>Пример компилироваться не будет, потому что компилятор потребует копирующий конструктор, V>который недоступен.
...Так требует стандарт (всем прикрыть глаза и благоговейно сказать о-о-о-о).
V>Но вот так подумать, зачем компилятору в этом случае копирующий конструктор? V>Какие промежуточные объекты создаютя в этом случае?
Дело в том, что стандарт допускает (но не требует) для этого случая оптимизацию
"constructor eliding" (поищи в стандарте слово elide).
То есть, если предположить, что конструктор копирования не требуется,
все будет работать, в случае, если компилятор выполняет "constructor eliding".
Но, с другой стороны, если компилятор этой оптимизации не выполняет, то работать это дело не будет...
Так что, стандарт рассчитывает на худший случай и мне кажется это есть хорошо.
__________
16.There is no cause so right that one cannot find a fool following it.
Re[2]: Возврат по значению и копирующий конструткор
Здравствуйте, Vamp, Вы писали:
V>Вот простой пример: V>
V>class A {
V> A();
V> A(const A&);
V>public:
V> A(int ) {}
V>};
V>A foo() {
V> return A(10);
V>}
V>int main() {
V>} //foo is never called!
V>
V>Пример компилироваться не будет, потому что компилятор потребует копирующий конструктор, который недоступен. Но вот так подумать, зачем компилятору в этом случае копирующий конструктор? Какие промежуточные объекты создаютя в этом случае?
Промежуточный объект ДОЛЖЕН создаваться, но его создание может быть позднее соптимизировано.
Ключевой момент — позднее.
Здравствуйте, Vamp, Вы писали:
V>Вот простой пример: V>
V>class A {
V> A();
V> A(const A&);
V>public:
V> A(int ) {}
V>};
V>A foo() {
V> return A(10);
V>}
V>int main() {
V>} //foo is never called!
V>
То, что foo is never called, ничего не значит: она вполне может быть called из другой единицы трансляции.
Так что компилятор совершенно прав, компилируя foo.
V>Пример компилироваться не будет, потому что компилятор потребует копирующий конструктор, который недоступен. Но вот так подумать, зачем компилятору в этом случае копирующий конструктор? Какие промежуточные объекты создаютя в этом случае?
Потому что у него так организована работа со стеком. Например, создается временный объект в кадре стека функции foo, а потом зовется конструктор копирования для принимающего объекта в кадре вызывающей функции.
Компилятору так удобнее, и Стандарт это разрешает.
Вот когда Стандарт скажет, что RVO обязательно к выполнению и тем самым упразднит обязательный вызов копиктора — тогда да.
P>Ну как минимум он нужен в return — вернее сам процесс возвращения значения... еслибы была ссылка — всё бы было хорошо. читаем Трупа Страуса_
Так в том и состоит вопрос — зачем он в return?
Да здравствует мыло душистое и веревка пушистая.
Re[3]: Возврат по значению и копирующий конструткор
Здравствуйте, Vamp, Вы писали:
PD>>Это он здесь never called. А в другом файле проекта у тебя V>... V>И? Вот при компиляции другой единицы и портебуется тот самый копи-конструктор.
ну код-то foo у тебя в первой единице трансляции и именно там он и будет лежать.
а в другой просто будет ссылка, которой займется линкер
DEA>Дело в том, что стандарт допускает (но не требует) для этого случая оптимизацию DEA>"constructor eliding" (поищи в стандарте слово elide).
Я так понимаю, что "constructor eliding" это нечто другое.
Я его понимаю так:
A a = foo(); -- вот здесь "constructor eliding" минует промежуточный копи-ктор из временного объекта в a. В моем случае я не понимаю, зачем что-то куда-то перекладывать. Почему функция не может создать свой объект сразу там, где он будет возвращен в вызывающий фрейм.
Да здравствует мыло душистое и веревка пушистая.
Re[2]: Возврат по значению и копирующий конструткор
Дело в том, что стандарт допускает (но не требует) для этого случая оптимизацию
"constructor eliding" (поищи в стандарте слово elide).
Т.е. в том случае если приведенный Вами код будет компилироваться на компиляторе, который такую оптимизацию не производит ( имеет право см. выше ), то код будет некорректным, т.е. налицо дуализм — код и компилируется (на одном типе компиляторов) и не компилируется ( на другом ) , поэтому оптимизирующие подобный код компиляторы и требуют конструктора копирования, дабы прсечь дуализм.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[3]: Возврат по значению и копирующий конструткор
Почему функция не может создать свой объект сразу там, где он будет возвращен в вызывающий фрейм.
class A {
A();
A(const A&);
public:
A(int ) {}
int GetInt();
};
A foo() {
A a;
...
// some action with a
...
return a;
}
int main() {
std::cout << foo().GetInt() << std::endl;
} //foo is never called!
Что где создавать?
Чему будет возвращено Если делать так как Вы говорите ?
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[4]: Возврат по значению и копирующий конструткор
S>>A foo() {
S>>
S>> A a;
S>> ...
S>> // some action with a
S>> ...
S>> return a;
S>>
S>>}
S>>
V>Это ведь не мой пример, правда? Речь шла про функцию в том виде, в котором она написана в моем случае.
Вы писали, чуть выше:
A a = foo(); -- вот здесь "constructor eliding" минует промежуточный копи-ктор из временного объекта в a. В моем случае я не понимаю, зачем что-то куда-то перекладывать. Почему функция не может создать свой объект сразу там, где он будет возвращен в вызывающий фрейм.
Именно не Ваш, поэтому и есть "constructor eliding" дабы не анализировать случай, приведенный мной
ИМХО: Благо он легко решается "constructor eliding" и не требует дополнительной логики.
Здравствуйте, Vamp, Вы писали:
V>Вот простой пример: V>
V>class A {
V> A();
V> A(const A&);
V>public:
V> A(int ) {}
V>};
V>A foo() {
V> return A(10);
V>}
V>int main() {
V>} //foo is never called!
V>
V>Пример компилироваться не будет, потому что компилятор потребует копирующий конструктор, который недоступен. Но вот так подумать, зачем компилятору в этом случае копирующий конструктор? Какие промежуточные объекты создаютя в этом случае?
Копирующий конструктор используется для создания возвращаемого значения.
"Как и передача аргументов, семантика возврата значения из функции идентична семантике инициализации."
Б. Страуструп
C++ ...., 7.3, стр.190
Feierlich, misterioso
Re[3]: Возврат по значению и копирующий конструткор
Здравствуйте, Vamp, Вы писали:
S>>Промежуточный объект ДОЛЖЕН создаваться, но его создание может быть позднее соптимизировано. V>Почему? Зачем?
Такова была изначальная семантика return. Разумеется, можно было бы вернуть объект вызовом его конструктора, но реализация этой фичи требует изменений в языке -- нужно вводить альтернативный оператор возврата коструированием, а не копированием.