إرجاع ifstream في وظيفة
سؤال
من المحتمل أن يكون هذا سؤالًا شديدًا جدًا بالنسبة لك: كيف (إذا كان ذلك ممكنًا) ، يمكنني إرجاع ifstream من وظيفة؟
في الأساس ، أحتاج إلى الحصول على اسم ملف قاعدة بيانات من المستخدم ، وإذا لم تكن قاعدة البيانات مع اسم الملف موجودًا ، فأنا بحاجة إلى إنشاء هذا الملف للمستخدم. أعرف كيفية القيام بذلك ، ولكن فقط عن طريق مطالبة المستخدم بإعادة تشغيل البرنامج بعد إنشاء الملف. أردت تجنب هذا الإزعاج للمستخدم إن أمكن ، لكن الوظيفة أدناه لا تتجمع في مجلس التعاون الخليجي:
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
تحرير: لقد قمت بتغيير الوظيفة لإرجاع مؤشر بدلاً من ذلك كما اقترح Remus ، وقمت بتغيير الخط في Main () إلى "Ifstream Database = *getFile ()" ؛ الآن أحصل على هذا الخطأ مرة أخرى ، ولكن هذه المرة في السطر في Main ():
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=
سيكون ضروريًا إذا وفقط إذا كان علينا نقل الحجة إلى CTOR. باستخدام دفق ، يمكننا إنشاء دفق لا يتصل بملف ، ثم استخدم Open للاتصال بالملف بعد الحقيقة.
لا يدعم Ifstream دلالات بنية النسخ (أن رسالة الخطأ بشكل أساسي SAIS) ، لذلك لا يمكنك إرجاع 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());
}