невозможно назначить или скопировать объект iostream? - PullRequest
2 голосов
/ 09 января 2012

iostream и другие потоковые классы не на самом деле класс, но typedef s, верно?

Вот проблема, я попытался инициализировать istream объект всписок инициализации, но, к сожалению, я получил ошибку, код выглядит следующим образом:

class A 
{
    public:
        A(istream &is=cin): ais(is)
        {}

    private:
        istream ais;
};

Невозможно скомпилировать с g ++, ошибка:

synthesized method ‘std::basic_istream<char, std::char_traits<char> >::basic_istream(const std::basic_istream<char, std::char_traits<char> >&)’ first required here 

Я искал SO, обнаружил, что iostream cannot be assigned or copy.Но почему я не могу инициализировать его в списке инициализации ?

Потому что я думаю, что список инициализации вызовет конструктор / copy-конструктор объекта, верно?

Ответы [ 6 ]

6 голосов
/ 09 января 2012

Ваш код пытается превратить одну istream, переданную в конструктор, в две istream с, переданную в конструктор и ais. Объект istream представляет сам этот реальный поток. Существует только один поток, и невозможно каким-либо образом превратить его в два потока.

Даже не ясно, что бы это значило. Если в потоке есть какие-то данные, получает ли тот поток, который читает сначала, их? Или они оба понимают это? Если да, то кто или что его дублирует?

istream подобен самому файлу . Вы не можете превратить один файл в два, не копируя данные из одного в другой самостоятельно. Однако вы можете иметь столько ссылок или указателей на тот же istream, сколько захотите. Возможно, решением вашей проблемы является ais ссылка.

4 голосов
/ 09 января 2012

У вас есть переменная-член, объявленная как:

istream ais;

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

Вы можете изменить переменную-член на ссылку:

istream& ais;

но это означает, что вы должны убедиться, что istream, на который ссылается ais, действителен в течение времени жизни A.

3 голосов
/ 09 января 2012

iostream и другие потоковые классы на самом деле не классы, а typedefs, верно?

Да, но это не имеет отношения.

Но почему я не могу инициализировать его в списке инициализации?

Потому что его нельзя ни скопировать, ни присвоить. Список инициализации Ctor не является магическим. Чтобы создать ais из is, вам нужно сделать копию, а вы не можете.

2 голосов
/ 09 января 2012

Объект stream представляет дескриптор потоков данных.Копировать это не имеет смысла.Кроме того, было бы неправильно копировать только базовую часть потока: это будет отрезать интересный бит (хотя вы можете получить действительно интересную часть, используя буфер потока).

То, что вы хотите инициализировать в своем классе, если он содержит поток, является ссылкой на поток:

std::istream& ais;

Конечно, это означает, что некоторым внешним необходимо поддерживать поток живым, пока выиспользуй это.Если это не то, что вам нужно или нужно, вы можете удерживать свой класс, например, std::ifstream и принимать std::string в качестве аргумента конструктора: если строка не пустая, вы открываете соответствующий файл.В противном случае вы установили бы для rdbuf() вашего потока значение из std::cin:

if (name.empty())
    ais.open(name.c_str());
else
    ais.rdbuf(std::cin.rdbuf());
1 голос
/ 09 января 2012
class A 
{
    public:
        A(istream &is=cin): ais(is)
        {}

    private:
        istream& ais;
};

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

1 голос
/ 09 января 2012

В дополнение к ответам, которые вы уже получили, вы также можете инициализировать ais (по вашему определению) с streambuf потока, который вы пропустили (конечно, с тем же предостережением, что и с применяется ссылка: Вы должны убедиться, что streambuf остается действительным до разрушения объекта).

Инициализация с базовым streambuf, вероятно, наиболее близка к копированию потока, который вы можете сделать: хотя оба все еще читают из одного файла и используют одну и ту же буферизацию (и другую обработку, которую может выполнять streambuf), все флаги форматирования и обработки ошибок являются отдельными.

Чтобы инициализировать ais с помощью streambuf, вы пишете:

class A 
{
public:
  A(std::istream& is = std::cin):
    ais(is.rdbuf())
  {
  }
private:
  std::istream ais;
};
...