Почему нельзя создать объект, содержащий элемент ostringstream?

У меня есть следующий пример класса, упрощенный из более крупного проекта. Он основан на структуре ведения журнала, которая использует область действия средства ведения журнала для завершения записи журнала в деструкторе.

Приведенный ниже код не будет компилироваться, поскольку конструктор представляет собой неявно удаленную функцию (edit: not true), которая, похоже, имеет какое-то отношение к объекту std::ostringstream. Я запутался в этом, потому что я думаю, что должен иметь возможность напрямую построить std::ostringstream, что означало бы, что я должен иметь возможность напрямую построить объект Container.

#include <iostream>
#include <sstream>

class Container {
  public:
    std::ostringstream  bufferStream;

  public:
    Container();    // constructor
    ~Container();
};

Container::Container() {
    bufferStream << "Hello ";
}

Container::~Container() {
    std::cout << bufferStream.str() << " [end]" << std::endl;
}

// === Main method ===

int main() {

    Container().bufferStream << "world";   // works fine

    {                                      // causes tons of compiler errors
        Container cont = Container();
        cont.bufferStream << "world!";
    }

    return 0;
}

Обратите внимание, что строка с надписью «отлично работает» делает именно это. Кажется, создается экземпляр анонимного объекта Container, который содержит новый std::ostringstream, к которому можно получить прямой доступ для вывода «мир». Сам Container создает часть сообщения "Hello", а его деструктор очищает буфер.

Почему вторая часть, в которой объект Container именуется и сохраняется, работает некорректно? Вот пример ошибок, которые я получаю:

error.cpp: In function ‘int main()’:
error.cpp:28:36: error: use of deleted function ‘Container::Container(const Container&)’
         Container cont = Container();
                                    ^
error.cpp:4:7: note: ‘Container::Container(const Container&)’ is implicitly deleted because the default definition would be ill-formed:
 class Container {
       ^
error.cpp:4:7: error: use of deleted function ‘std::basic_ostringstream<char>::basic_ostringstream(const std::basic_ostringstream<char>&)’
In file included from error.cpp:2:0:
/usr/include/c++/4.8/sstream:387:11: note: ‘std::basic_ostringstream<char>::basic_ostringstream(const std::basic_ostringstream<char>&)’ is implicitly deleted because the default definition would be ill-formed:
     class basic_ostringstream : public basic_ostream<_CharT, _Traits>

... и так далее.


person Ethan T    schedule 04.04.2016    source источник
comment
Э-э, это не обман этот вопрос.   -  person Barry    schedule 04.04.2016


Ответы (2)


Это будет работать нормально:

Container cont;
cont.bufferStream << "world!";

Но это:

Container cont = Container();

включает конструктор копирования. std::ostringstream не является копируемым, что делает Container не копируемым, поэтому сообщение об ошибке, говорящее о том, что Container::Container(const Container&) неявно удаляется из-за неявного удаления std::basic_ostringstream<char>::basic_ostringstream(const std::basic_ostringstream<char>&).

Обратите внимание, что даже если эта копия будет исключена, требование исключения копирования/перемещения состоит в том, что копирование/перемещение должно быть возможным с самого начала.

person Barry    schedule 04.04.2016
comment
Идеально. Таким образом, правильный оператор Container cont; создает контейнер, но не копирует его. Мой фон Java отображается! - person Ethan T; 04.04.2016
comment
... и он вызывает конструктор копирования, потому что предоставленный пользователем деструктор подавляет неявный конструктор перемещения. - person T.C.; 04.04.2016

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

Однако если вы следуете правилу трех, вы создаст конструктор копирования (а также оператор присваивания копии), делает то, что нужно для строкового потока. Тогда это сработает:

class Container {
    ...
    Container(const Container&); //Copy constructor
};  

Container::Container(const Container &c) {
    bufferStream << c.bufferStream.rdbuf(); 
}

Онлайн-демонстрация

person Christophe    schedule 04.04.2016