16

I am a C++ beginner, so sorry if the question is too basic.

I have tried to collect the string constrcturs and try all them out (to remember them).

string strA();          // string(); empty string // incorrect
string strB("Hello");   // string( const char* str)
string strC("Hello",3); // string( const char* str, size_type length)
string strD(2,'c');     // string( size_type lenght, const char &c)
string strE(strB);      // string( const string& s)

cout << strA << endl;
cout << strB << endl;
cout << strC << endl;
cout << strD << endl;
cout << strE << endl;

All of them works except for the strA. It prints "1". Why? Whats the type of the strA in this case? How can I check the type of stuff when I am unsure?

I have noticed that the correct way is this (which by the way seems to be inconsistent with the other constructors, sometimes parens sometimes no parens):

string strA;

ps: question in bold, usual irrelevant answers will be downvoted.

0

7 Answers 7

32

This is a very popular gotcha. C++ grammar is ambiguous. One of the rules to resolve ambiguities is "if something looks like declaration it is a declaration". In this case instead of defining a variable you declared a function prototype.

string strA();

is equivalent to

string strA(void);

a prototype of a no-arg function which returns string.

If you wish to explicitly call no-arg constructor try this:

string strA=string();

It isn't fully equivalent - it means 'create a temporary string using no-arg constructor and then copy it to initialize variable strA', but the compiler is allowed to optimize it and omit copying.

EDIT: Here is an appropriate item in C++ FAQ Lite

Sign up to request clarification or add additional context in comments.

3 Comments

And this is one reason why I stopped using C++.
@Dietrich Epp : This bothered me, too. I guess this is the price paid to keep C compatibility. The alternative being using C, which has its metric ton of problems, my guess is that it's better to keep C++ and avoid that pitfall.
how about std::string strA("");
14

It considers

string strA();

as a function declaration.

For default constructor use:

string strA;

1 Comment

You may use that notation when allocating off the heap: string* strA = new string();
6

In C++, as in C, there is a rule that says that anything that looks like a declarartion will be treated as a declaration.

string strA();

looks like a function declaration, so it is treated as one. You need:

string strA;

Comments

4

I don't think that in this case, the rule "if it could be a declaration, it's taken to be a declaration" applies. Since in the following, both things are declarations

string a;
string a();

The one is the declaration of an object, and the other is the declaration of a function. The rule applies in other cases. For example, in this case:

string a(string());

In that case, string() can mean two things.

  • Declaration of an unnamed function parameter
  • Expression creating a default constructed string

The fule applies here, and string() is taken to mean the same as the following, named parameter (names are irrelevant in parameters when declaring a function)

string a(string im_not_relevant());

If a function takes as parameter an array or another function, that parameter decays into a pointer. In case of a function parameter, to a pointer to the function. Thus, it is equivalent to the following, which may look more familiar

string a(string (*im_not_relevant)());

But in your case, it's rather the syntax that's getting into the way. It's saying that the following is a function declaration. It can never be the declaration of an object (even though that was probably intended by the programmer!)

string a();

So there is no ambiguity in this context in the first place, and thus it declares a function. Since string has a user defined constructor, you can just omit the parentheses, and the effect remains the same as what was intended.

Comments

3

It prints 1 because pointers to functions are always converted to numeric as true.

1 Comment

Only if the pointer to function is non-null. Anyway, a pointer to function should point to its definition, and that's missing here. This shouldn't have linked.
2

tkopec is right on why it doesn't work. To answer your second question, here's how you check the type:

template<typename TEST> void Error_() {
   TEST* MakeError = 1;
}

By calling Error_(StrA); you will get a compile error, and your compiler will probably tell you that it happened in Error_< std::basic_string<char, std::allocator<char> > (*)(void)>(std::basic_string<char, std::allocator<char> > (*)(void)) Now, std::basic_string > is just std::string, so this really means Error_< std::string (*)(void)> (std::string (*)(void)). The part between '<>' is repeated between '()', and that's the sype of strA. In this case, std::string (*)(void).

1 Comment

Type of strA is a function. std::string(void) . It's not a function pointer. He would have to declare it as string (*strA)(); if he wanted it to be a function pointer. I probably know what you meant, but your last sentences sound like you say it's a function pointer.
1

Compiler interprets string strA() as a function prototype of a function which takes void arguments and returns an object of string type. If you want to create a empty string object use string strA; (without paranthesis)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.