这里有可能是你一个非常noobish问题:我如何(如果可能的话)可以从一个函数返回一个ifstream的?
基本上,我需要获得来自用户的数据库文件名,如果与文件名的数据库不存在,那么我需要为用户创建该文件。我知道该怎么做,但只能通过询问用户创建文件后重新启动该程序。我想避免用户如果可能的不便,但下面的功能不会GCC编译:
ifstream getFile() {
string fileName;
cout << "Please enter in the name of the file you'd like to open: ";
cin >> fileName;
ifstream first(fileName.c_str());
if(first.fail()) {
cout << "File " << fileName << " not found.\n";
first.close();
ofstream second(fileName.c_str());
cout << "File created.\n";
second.close();
ifstream third(fileName.c_str());
return third; //compiler error here
}
else
return first;
}
编辑:对不起,忘了告诉你,什么编译器错误是:
main.cpp:45: note: synthesized method ‘std::basic_ifstream<char, std::char_traits<char> >::basic_ifstream(const std::basic_ifstream<char, std::char_traits<char> >&)’ first required here
编辑:我改变该函数返回一个指针,而不是作为瑞摩斯建议,并且在主换了线()为“ifstream的数据库= *的GetFile()”;现在我再次得到这个错误,但是这一次在主线路():
main.cpp:27: note: synthesized method ‘std::basic_ifstream<char, std::char_traits<char> >::basic_ifstream(const std::basic_ifstream<char, std::char_traits<char> >&)’ first required here
bool checkFileExistence(const string& filename)
{
ifstream f(filename.c_str());
return f.is_open();
}
string getFileName()
{
string filename;
cout << "Please enter in the name of the file you'd like to open: ";
cin >> filename;
return filename;
}
void getFile(string filename, /*out*/ ifstream& file)
{
const bool file_exists = checkFileExistence(filename);
if (!file_exists) {
cout << "File " << filename << " not found." << endl;
filename = getFileName(); // poor style to reset input parameter though
ofstream dummy(filename.c_str();
if (!dummy.is_open()) {
cerr << "Could not create file." << endl;
return;
}
cout << "File created." << endl;
}
file.open(filename.c_str());
}
int main()
{
// ...
ifstream file;
getFile("filename.ext", file);
if (file.is_open()) {
// do any stuff with file
}
// ...
}
不,不是真的。 ifstream
没有一个拷贝构造函数,如果你试图返回一个,这意味着在复制你的函数实例进行到哪里返回需要去。
通常的解决方法是在参考传递到一个,并修改你的函数引用。
编辑:同时,让你的代码工作,也不会解决根本问题。现在,你将两种完全不同的责任纳入一个单一的功能:1)获取文件名,2)打开或创建该文件。我想,如果你把这些分开,代码会更简单,使之更容易消除你看到了问题的根源。
编辑2:使用这样的参考工作得很好没有operator=
。总的想法是这样的:
int open_file(char const *name, fstream &stream) {
stream.open(name);
}
赋值运算符是既无必要,也有用在这种情况下 - 我们只需通过参考使用现有的fstream。一个operator=
是必要的,当且仅当我们必须传递参数的构造函数。随着甲流,我们可以默认构造不连接到文件流,然后用开放连接到事后的文件。
ifstream的不支持复制构建语义(那个什么错误讯息基本上最高审计机关),所以你不能返回ifstream的。返回一个ifstream的*代替,并传递给调用者的责任以删除分配指针。
这一评论可能不回答你的问题,我只想问@Corwin先生对他的回答:就像他的代码,我们有:getFileName
块请求的文件名,我想我们应该像这样的代码(这是我认为唯一的):
void getFile(/*out*/ ifstream& file){
string filename = getFileName();
const bool file_exist = checkFileExistence(filename);
if (!file_exist){
....
}
....
}
而在int main()
,我认为:
int main(){
ifstream file;
getFile(file);
if (file.is_open()){
//some stuff
}
}
有了这个,你可以在控制台根据用户输入得到filename
。
通过的途径,感谢@Corwin先生代码它的帮助了我很多。
作为一个选项,ifstream的可扩展和自定义构造函数添加到新类。
我已经扩展它来创建测试资源流,封装在它的内部测试资源查找。
// test_utils.h
class TestResourceStream : public std::ifstream {
public:
TestResourceStream(const char* file_path);
};
// test_utils.cpp
namespace fs = std::filesystem;
fs::path test_resource_path(const char* file_path) {
fs::path path{std::string{"tests/resources/"} + file_path};
if (!fs::exists(path))
throw std::runtime_error{std::string{"path "} +
fs::absolute(path).c_str() + " does not exist"};
return path;
}
TestResourceStream::TestResourceStream(const char* file_path)
:std::ifstream{test_resource_path(file_path).c_str()} {}
// usage in test
TEST_CASE("parse") {
std::list<GosDump::Expertise> expertises;
TestResourceStream stream("requests/page_response.json");
GosDump::Json::parse(expertises, stream);
REQUIRE(10 == expertises.size());
}