Как вы можете передать 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))
{
}