Как вы можете передать std:: istream в функцию таким образом, что позволяет передавать временные файлы?

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

Loader::Loader(istream stream);

это явно плохо из-за нарезки объектов, поэтому нет выбора.

Loader::Loader(istream& stream);

это то, что я использую сейчас, и, кажется, довольно хорошо. У этого есть одна существенная проблема, хотя - вы не можете дать ему временное, так как временные не могут привязываться к неконст-ссылкам! Например, следующее не будет работать:

Container():
  mLoader(ifstream("path/file.txt", ios::binary)
{
}

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

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

Loader::Loader(const istream& stream);

но с тех пор .seek () и т. д. не являются const,это также не вариант...

Итак,как эта проблема может быть решена аккуратно?

3 ответов


если ваш компилятор c++11 или лучше, вы можете просто предоставить версию конструктора, который принимает istream в качестве ссылки на r-значение:

void Loader::Loader(std::istream&& is)

пример:

#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>

struct Loader
{
    Loader(std::istream& is)
    {
        read(is);
    }

    Loader(std::istream&& is)
    {
        read(is);
    }

    void read(std::istream& is)
    {
        is >> std::quoted(x);
        is >> std::quoted(y);
    }

    std::string x, y;
};

std::ostream& operator<<(std::ostream& os, const Loader& l)
{
    os << "x = " << l.x;
    os << ", y = " << l.y;
    return os;
}


auto main() -> int
{
    using namespace std;

    Loader l(istringstream(R"text("donkey" "horse")text"));
    cout << l << endl;

    istringstream not_temp(R"text("apple" "banana")text");
    Loader l2(not_temp);
    cout << l2 << endl;

    return 0;
}

ожидаемый результат:

x = donkey, y = horse
x = apple, y = banana

пример

Container():
  mLoader(ifstream("path/file.txt", ios::binary)
{
}

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

однако, технически, для того, чтобы иметь возможность передать временный ссылку на-не -const формальный аргумент, просто определите небольшой помощник, как это:

template< class Type >
auto temp_ref( Type&& o )
    -> Type&
{ return o; }

затем вы можете позвонить, например,foo( temp_ref( Whatever() ) ), но и просто держать в имейте в виду, что жизнь этого временного-это полное выражение, в котором оно происходит.


передача указателя на вновь созданный объект будет работать.

Loader(istream * pstream)
{
    try
    {
        // ......

        delete pstream;
        throw; 
    }
    catch(...)
    {    
        delete pstream;                  
    }
}

Container():
mLoader(new ifstream("path/file.txt", ios::binary))
{
}