std::vector::emplace_back(...)
От: HolyNick  
Дата: 17.07.14 14:05
Оценка:
Добрый день.
Никто не подскажет почему такой код компилируется только когда у Foo определен конструктор копирования, при этом он не вызывается.
Когда конструктор копирования отсутствует, "ругается на" (что он delete) конструктор копирования fstream.

class Foo
{
public:
    Foo(){}
    Foo(const Foo& f){}
private:
    std::fstream f;
};

class Bar
{
public:
    Bar(int i){}
    Foo foo;
};

std::vector<Bar> v;
v.emplace_back(5);


Спасибо.
Re: std::vector::emplace_back(...)
От: HolyNick  
Дата: 17.07.14 14:58
Оценка:
Снимается вопрос.
Re[2]: std::vector::emplace_back(...)
От: HolyNick  
Дата: 17.07.14 15:14
Оценка:
Хотя нет — не снимается.
Re[3]: std::vector::emplace_back(...)
От: Lukkoye  
Дата: 17.07.14 21:07
Оценка:
Здравствуйте, HolyNick, Вы писали:

HN>Хотя нет — не снимается.


Потому что вопреки досужим мнениям, язык с++ является статически строго типизированным. А это означает, что он на нем нельзя выполнять семантику присвоения теплого с мягким:

some val = 10;

Что здесь происходит?

Некоторые думают, что данный код эквивалентен:

some val(10);

Но это ошибочное мнение. Поскольку язык строго типизированный, то когда используется семантика присвоение (символ '='), в левой и в правой части должны находится идентичные типы данных.

Поэтому настоящий эквивалент кода выглядит так:

some val = some(10);

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

Окончательная версия эквивалента получается такой:

some val( some(10) );

При этом срабатывает стандартная NRVO-оптимизация, и мы не наблюдаем вызова конструктора копии. Даже в дебаге не наблюдаем.

Вообще согласно стандарту, вы не должны закладываться на наблюдаемость копирующих конструкторов, потому что они являются претендентами на оптимизацию.
Re: std::vector::emplace_back(...)
От: uzhas Ниоткуда  
Дата: 18.07.14 07:28
Оценка:
Здравствуйте, HolyNick, Вы писали:

HN>Добрый день.

HN>Никто не подскажет почему такой код компилируется только когда у Foo определен конструктор копирования, при этом он не вызывается.

предположу, что для типа Bar нужно предоставить либо конструктор копирования, либо конструктор перемещения. для emplace_back тип должен быть EmplaceConstructible, MoveInsertable, MoveAssignable, Erasable
std::fstream не имеет конструктора копии или конструктора перемещения, поэтому компилятор не смог сгенерировать соответствующие конструкторы для типа Foo. когда вы вручную определяете Foo(const Foo&) {}, то компилятору становится хорошо, но пустой конструктор копирования не копирует std::fstream, ваше приложение может неправильно работать из-за этого

все это можно найти в стандарте глава 23 Containers library [containers]
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.