LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   C++ constructor (https://www.linuxquestions.org/questions/programming-9/c-constructor-4175677761/)

Jerry Mcguire 06-28-2020 12:29 AM

C++ constructor
 
It sounds simple enough when trying to open a file or to test the existence of a file.

Code:

{
  std::ifstream f("filename");
  if (f) {
    // file exists
  }
}

My question is, what is f when "filename" does not exist? To do the same in my own classes, how to write the constructor that returns that "null" object?

SoftSprocket 06-28-2020 12:42 AM

That shouldn't compile. f isn't something that can be implicitly converted to a boolean. To be a NULL object it would have to be a pointer of sometype (in modern c++ a nullptr). To test the f object you can use the state functions (i.e. good, bad, fail). A constructor can't return a null object.

EdGr 06-28-2020 01:08 AM

There is nothing wrong with writing C in a C++ program:

Code:

FILE *fp;
fp=fopen ("filename", "r");
if (fp) {
  // file exists
}

Ed

Jerry Mcguire 06-28-2020 01:13 AM

It does compile. I used this technique to do quick checks for flag file all the time.

After some "stepping into", I see 'f' returned is a valid object when "filename" does not exist. That leaves me wonder why the statement "if (f) {}" will work. My closest attempt is this:

Code:

#include <iostream>
#include <fstream>

int main()
{
        std::ifstream iF("foo");
        if (iF) {
                std::cerr << "foo exists.\n";
        }
        else {
                std::cerr << "foo not exists.\n";
        }

        class MyClass {
        public:
                operator bool() { return false; } // sucks
        };

        MyClass c;
        if (c) {
                std::cerr << "c valid.\n";
        }
        else {
                std::cerr << "c not valid.\n";
        }
}


Jerry Mcguire 06-28-2020 01:16 AM

Quote:

Originally Posted by EdGr (Post 6138771)
There is nothing wrong with writing C in a C++ program:

Thanks. But my point is how to implement your own classes to enjoy the benefit of this construct:
Code:

MyClass c;
if (c) {
  // I'm good to go.
}
else {
  // No go, get help.
}

I don't want to throw exception.

EdGr 06-28-2020 01:30 AM

Quote:

Originally Posted by Jerry Mcguire (Post 6138774)
Thanks. But my point is how to implement your own classes to enjoy the benefit of this construct:
Code:

MyClass c;
if (c) {
  // I'm good to go.
}
else {
  // No go, get help.
}

I don't want to throw exception.

As SoftSprocket said, the constructor cannot fail. "c" will never be NULL. You need to create and test a member function like c->success ().

IMO, this is much more convoluted than the C method.

ETA: My comment assumed "c" was declared as a pointer to MyClass and allocated with new.
Ed

Jerry Mcguire 06-28-2020 06:20 AM

No it is not solved.

Code:

  std::ifstream f("filename");
  if (f) { // <--
  }

Could any one help us understanding how does the if-clause interpret (f) at the <-- statement.

SoftSprocket 06-28-2020 08:57 AM

Well, some where I missed this. fstream overloads the !operator so that !f is a synonym for fail https://en.cppreference.com/w/cpp/io..._ios/operator!

pan64 06-28-2020 09:05 AM

I think that was already explained.
std::ifstream f(<anything>) is a constructor which will create a c++ object named f. Probably usable, but probably useless. Anyway, the class is created.
if (anything) is interpreted quite easily: anything is converted to a number (if that was not a number already). f is a non-null object, therefore it will be converted to a non-zero number. Finally if will check if that number (result) was non-zero (in your case it is most probably the pointer to the class instance).

http://www.cplusplus.com/reference/f...tream/is_open/

EdGr 06-28-2020 09:50 AM

"bool" is being overloaded. The function call is implied. http://www.cplusplus.com/reference/i.../operator_bool

IMO, overloading is a terrible feature. A reader can't look at code and figure out what it does without also looking at a bunch of declarations. It is much better to explicitly call the appropriate function.
Ed

SoftSprocket 06-28-2020 10:01 AM

Actually, it's not a pointer , it's a class object and it can't be converted to a number but since the !operator (and bool operator) is overloaded you can test it with a bool operation.
i.e.
Code:

class A {
        public:
                operator bool () {
                        return true;
                }

                bool operator! () {
                        return false;
                }

};


Jerry Mcguire 06-28-2020 11:06 AM

Then it's no magic. Just operator bool().

Code:

{
        class MyClass {
        public:
                MyClass(const std::string& filename)
                        : iF(filename)
                {
                }
                std::ifstream iF;
                explicit operator bool() const { return static_cast<bool>(iF); } // <-- Ha!
        };

        MyClass c( "foo" );
        if (c) {
                std::cerr << "foo valid.\n";
        }
        else {
                std::cerr << "foo not valid.\n";
        }
}

Thanks.

dugan 06-28-2020 10:09 PM

After a quick trip to http://www.cplusplus.com/reference/f...ream/ifstream/

Code:

#include <iostream>
#include <fstream>

int main()
{
  using namespace std;
  ifstream f("nonexistent");
  cout << f.fail() << "\n";
  return 0;
}

That prints "1".

dugan 06-28-2020 10:17 PM

Quote:

Originally Posted by Jerry Mcguire (Post 6138757)
It sounds simple enough when trying to open a file or to test the existence of a file.

Code:

{
  std::ifstream f("filename");
  if (f) {
    // file exists
  }
}

My question is, what is f when "filename" does not exist? To do the same in my own classes, how to write the constructor that returns that "null" object?

I'm sorry, what am I reading here?

There is absolutely nothing wrong with the way you're checking for the file's existence.

Obviously, if you also want to handle the file not existing, you'd extend the code to:

Code:

{
  std::ifstream f("filename");
  if (f) {
    // file exists
  } else {
    // file does not exist
  }
}

I assume you already knew that.

And as for this:

Code:

how to write the constructor that returns that "null" object?
Quote:

Originally Posted by Jerry Mcguire (Post 6138774)
Thanks. But my point is how to implement your own classes to enjoy the benefit of this construct:
Code:

MyClass c;
if (c) {
  // I'm good to go.
}
else {
  // No go, get help.
}

I don't want to throw exception.

Well, there are some options...

Obviously, it is impossible for the constructor to ever return nullptr. That's not how constructors work.

You said "null object", and that actually is a pattern that you can use to solve this. https://en.wikipedia.org/wiki/Null_object_pattern#C++

Another option is to have a state variable on the class that determines whether or not the file exists. That's the pattern for Qt code, which does not use exception handling.

If you want the correct suggestion, then it actually is "throw an exception".

https://isocpp.org/wiki/faq/exceptions#ctors-can-throw

NevemTeve 06-28-2020 11:28 PM

(It is hard to follow 'the standard C++ ways' as C++ is an union of many different concepts. That's why some contructors throw exceptions, others create a 'marked as broken' object.
IMHO Yossi Kreinin's C++ FQA is a mandatory reading for a beginner.)

dugan 06-29-2020 10:26 AM

Of course, another option is to overload the ! operator like ifstream does. I'd probably take that option for consistency.


All times are GMT -5. The time now is 03:47 PM.