LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Constructor takes string => constructor not called...? (C++) (https://www.linuxquestions.org/questions/programming-9/constructor-takes-string-%3D-constructor-not-called-c-929669/)

JohnGraham 02-16-2012 05:04 AM

Constructor takes string => constructor not called...? (C++)
 
Hi there,

I have a File class and I want to call its constructor. It has three constructors, they look like this:

Code:

File(int fd = -1);                    // Construct from file descriptor...
File(const std::string &name, Mode);  // ...from file name + open mode...
File(const File &file);              // ...or from other descriptor.

In a simple program (that at the moment just opens a file to see if it is there) I accidentally called it with just a string argument - i.e.:

Code:

// Using just "File file(argv[1])" seemed to want to use the
// constructor that takes an int.
File file(std::string(argv[1]));

I got no compile-time error, and the output of nm shows no symbol relating to the File class is used (i.e. the output of "nm program|grep File"). When the program was run, no exception was thrown if the file didn't exist, as I would have expected.

When I change the call to:

Code:

File file(std::string(argv[1]), File::RdOnly);
I get both (i) the symbols for the appropriate constructor and destructor in the output file and (ii) the correct behaviour (i.e. an exception being thrown) if the file doesn't exist.

Can anybody tell me what's going on here?

ta0kira 02-16-2012 08:22 AM

Do you have a derived class with File as a base containing a constructor that takes a single std::string argument? You might try declaring all of your constructors (other than default and copy) explicit.
Kevin Barry

JohnGraham 02-16-2012 10:17 AM

Thanks for the suggestion - no, the only derived class is Socket and that has no such constructor. Also, File does not derive from any class. Still, declaring the instance like "File file(/* args */)" surely should never cause any other constructor to be called, derived or otherwise, should it?

dwhitney67 02-16-2012 10:42 AM

Quote:

Originally Posted by JohnGraham (Post 4603913)
Can anybody tell me what's going on here?

You are declaring a function with this statement (sort of what one would do in C using the extern keyword):
Code:

File file(std::string(argv[1]));
The function, called file(), accepts a pointer to an std::string argument, and returns a File object.

I wish I could offer a better explanation on how to avoid errors like this; as you discovered, the compiler does not issue any warning/error. Try calling the function file() with an std::string parameter, and then you will get the error.

Play with the code that is commented out:
Code:

#include <string>
#include <iostream>

typedef int Mode;

class File
{
public:
    File(int fd = -1)
    {
        std::cout << "File constructor for fd called." << std::endl;
    }

    File(const std::string& name, Mode mode)
    {
        std::cout << "File constructor for name and mode called." << std::endl;
    }

    File(const File& other)
    {
        std::cout << "File copy constructor." << std::endl;
    }

    ~File()
    {
        std::cout << "File destructor called." << std::endl;
    }
};

int main(int argc, char** argv)
{
    File file(std::string(argv[1]));

    std::string foo = "foo";
    //file(&foo);
}


File file(std::string* s)
{
    std::cout << "file() called with string " << s << "." << std::endl;

    return File();
}


ta0kira 02-16-2012 12:37 PM

Quote:

Originally Posted by dwhitney67 (Post 4604194)
You are declaring a function with this statement (sort of what one would do in C using the extern keyword):
Code:

File file(std::string(argv[1]));
The function, called file(), accepts a pointer to an std::string argument, and returns a File object.

To me it makes very little sense that in this context std::string(argv[1]) is the same as std::string argv[1], but that appears to be the case. I actually had to look it up, and indeed this exact type of ambiguity is addressed in C++03 §8.2.1. What's more annoying is this (see 8.2.7):
Code:

struct F
{
        F(int) {}
};

struct A;

namespace X {
struct B;
}

int main()
{
        F func1(int(A));
        F func2(int(B));

        char A;
        using X::B;

        F func1(int(B));
        F func2(int(A));

        func1(0); //<-- ambiguous
        func2(0); //<-- 'func2' isn't overloaded
}

Code:

test.cpp: In function 'int main()':
test.cpp:23:9: error: call of overloaded 'func1(int)' is ambiguous
test.cpp:14:4: note: candidates are: F func1(int (*)(A))
test.cpp:20:4: note:                F func1(int (*)(X::B))

Kevin Barry


All times are GMT -5. The time now is 12:43 AM.