is it wrong to call a method outside main() - c++

I was wondering if someone could explain the meaning of the following error:
CODE
#include "sstream"
std::stringstream h;
h.str(""); //clearing the stringstream object
int main()
ERROR
kial.cpp:5:1: error: ‘h’ does not name a type h.str("");
Also why is it wrong to try to access the method ouside of the main()?

OK, so everyone landed here with a simple statement saying that you cannot do it. Trust no one. In fact, you can. But not like you have tried to do it. Generally, you cannot have statements like function calls outside other functions. And the first function to get called is always main. However, C++ has RAII and global objects. Therefore, there is only one exception to the above rule - construction and destruction of global objects. By employing RAII and declaring some object global, you can have its constructor called, and do the rest from there. So for example, you could solve you problem like this:
#include <sstream>
#include <iostream> // just for std::cout and std::endl.
std::stringstream h;
struct MyStruct {
MyStruct() {
h.str(""); //clearing the stringstream object
std::cout << "`h` string stream is cleared now!" << std::endl;
}
};
MyStruct mystruct;
int main()
{
std::cout << "I am called AFTER MyStruct's constructor" << std::endl;
}
Compile and run:
$ g++ -Wall -pedantic -std=c++98 ./test.cc && ./test
`h` string stream is cleared now!
I am called AFTER MyStruct's constructor
Hope it helps. Good Luck!

The compiler is assuming you tried to make a declaration (or a definition), since general statements are not allowed at global scope.
The short answer to why this is not allowed is that the standard says so.
To think through why that is the answer, consider when you would expect the code to execute. What does it mean to call a function at global (or namespace) scope, given the already-defined order of execution of a program?
If you really have something you need to do at that scope, you can always use an instance of a class whose constructor does what you want.

Related

Are default arguments of object type constructed every time they aren't specified?

I've seen some code where there is a method with some default arguments which are of object type and it got me wondering what happens when the default arguments aren't specified by a caller. In "The C++ Programming Language" Stroustrup says this:
A default argument is type checked at the time of the function declaration and evaluated at the time of the call.
For example, if there is a method declared like this will it a new string be constructed every time this method is called without passing in default_string?:
void foo(int param, std::string default_string = {});
The reason I was wondering about this was if I were to implement such a method where callers more often than not don't provide the default arguments would it be better to not use default arguments at all and define two methods with and without these arguments to avoid costly construction of unused arguments?
Yes.
#include <iostream>
struct Object {
Object(bool expensive = true) {
if (expensive) {
std::cout << "Oh, I am so expensive!" << std::endl;
} else {
std::cout << "Ah, this was cheap." << std::endl;
}
}
};
void foo(Object o = {}) {}
int main() {
foo(Object(true));
foo(Object(false));
foo();
foo();
return 0;
}
[:~/tmp] $ g++ -std=c++2a constr2.cpp && ./a.out
Oh, I am so expensive!
Ah, this was cheap.
Oh, I am so expensive!
Oh, I am so expensive!
Note that the compiler cannot omit the construction of Object if it cannot prove that it has no side-effects. In the example, even if it realizes that o will not be used in the body of foo, it cannot leave out the print.

c++ anonymous constructor doing weird things

This sample program shows how a different constructor will be called depending on whether you pass in a local variable, a global variable, or an anonymous variable. What is going on here?
std::string globalStr;
class aClass{
public:
aClass(std::string s){
std::cout << "1-arg constructor" << std::endl;
}
aClass(){
std::cout << "default constructor" << std::endl;
}
void puke(){
std::cout << "puke" << std::endl;
}
};
int main(int argc, char ** argv){
std::string localStr;
//aClass(localStr); //this line does not compile
aClass(globalStr); //prints "default constructor"
aClass(""); //prints "1-arg constructor"
aClass(std::string("")); //also prints "1-arg constructor"
globalStr.puke(); //compiles, even though std::string cant puke.
}
Given that I can call globalStr.puke(), I'm guessing that by calling aClass(globalStr);, it is creating a local variable named globalStr of type aClass that is being used instead of the global globalStr. Calling aClass(localStr); tries to do the same thing, but fails to compile because localStr is already declared as a std::string. Is it possible to create an anonymous instance of a class by calling its 1-arg constructor with a non-constant expression? Who decided that type(variableName); should be an acceptable way to define a variable named variableName?
aClass(localStr); //this line does not compile
This tries to declare a variable of type aClass named localStr. The syntax is terrible, I agree, but it's way too late for that [changing the standard] now.
aClass(globalStr); //prints "default constructor"
This declares one called globalStr. This globalStr variable hides the global one.
aClass(""); //prints "1-arg constructor"
This creates a temporary object of type aClass.
aClass(std::string("")); //also prints "1-arg constructor"
This also creates a temporary.
globalStr.puke(); //compiles, even though std::string cant puke.
This uses the globalStr in main, which is consistent with every other instance of shadowing.
Is it possible to create an anonymous instance of a class by calling its 1-arg constructor with a non-constant expression?
Yes, I can think of four ways:
aClass{localStr}; // C++11 list-initialization, often called "uniform initialization"
(void)aClass(localStr); // The regular "discard this result" syntax from C.
void(aClass(localStr)); // Another way of writing the second line with C++.
(aClass(localStr)); // The parentheses prevent this from being a valid declaration.
As a side note, this syntax can often be the cause of the Most Vexing Parse. For example, the following declares a function foo that returns aClass, with one parameter localStr of type std::string:
aClass foo(std::string(localStr));
Indeed it's the same rule that's responsible for your problems - If something can be parsed as a valid declaration, it must be. That is why aClass(localStr); is a declaration and not a statement consisting of a lone expression.

Calling copy constructor on yourself

I am curious about what is happening in this code I wrote almost by mistake:
#include <iostream>
class Test
{
public:
Test() {
std::cout << "Default constructor";
a= 10;
}
int a;
};
int main() {
Test obj(obj);
std::cout << obj.a << std::endl;
}
It compiles in gcc without warnings of any kind (using -Wall -Werror).
Executing it only prints garbage.
If I am not mistaken, this is calling the implicit copy-constructor on itself, without ever initialising. I am curious about what the copy-constructor would do in such a situation, but gdb will not stop in that line (breakpoints set to that line jump to the next one).
Everything breaks if "complex" attributes are added to the class (like a std::string), probably because of how the '=' operator is overloaded for such classes.
Is my hypothesis correct? Why doesn't gdb stop in that line? Why no warnings when calling a copy constructor with an uninitialised object?
Since you have a member variable of type int, whose indeterminate value is copied to itself, the code is technically Undefined Behavior.
However, in practice, with current computers nothing bad will happen. But on the third hand, nothing good happens either.
Regarding warnings, that's a Quality Of Implementation issue. The C++ standard has nothing to say about that.

Eliminating of variable with static storage duration

I came across the following rule (3.7.1/2 N3797):
If a variable with static storage duration has initialization or a
destructor with side effects, it shall not be eliminated even if it
appears to be unused, except that a class object or its copy/move may
be eliminated as specified in 12.8.
Is it true that, if we declare a variable with static storage duration, having constructor or destructor with side-effect, then the memory will allocate for that variable even if it is unused?
In particular, I'm trying to experiment with the following code:
#include <csignal>
#include <iostream>
#include <cstdlib>
using std::cout;
struct data_member
{
data_member(){ cout << "data_member\n"; }
~data_member(){ cout << "~data_member\n"; }
};
struct Y
{
static data_member m;
Y(){ cout << "Y\n"; }
~Y(){ cout << "~Y\n"; }
};
Y y;
int main()
{
}
IdeOne
Why does data_member object not constructed in the example?
Well, that's what the standard says, so ... yes.
As always, there's the as-if rule, allowing a compiler to do practically anything, as long as the net effect is the same. I could imagine that if the class is huge data-wise, but the constructor and destructor (and anybody else) do not access that data, the compiler could just call the constructor and destructor in the proper order, without leaving space for the unused data.
As for your example, you're declaring Y::m, but you never define it. So it doesn't exist. If you tried to access it, you'd get a linker error.

C++ redefiniton of 'name' with a different type compiler warning

Why do the compiler complain redefiniton of 'reader' with a different type when I try to pass an fstream object from main() into another class´s constructor for it to be read? I am aware of this is maybe i dumb way of doing it, I should really just have a string as parameter asking for filename then pass that into the fstream that I allocate in the constructor of the class. But anyways I am wondering why this don´t work, the compiler warning is cryptic.
my main function:
fstream reader;
reader.open("read.txt");
Markov(reader);
Constructor in Markov.h class:
class Markov {
public:
/** Constructor */
Markov(fstream inStream) {
Map<string, Vector<string> > array0;
char ch;
while (inStream.good())
{
ch = inStream.get();
cout << ch << endl;
}
cout << "End: " << ch;
order0(array0);
}
The line Markov(reader); is creating a variable called reader of type Markov. It is equivalent to the following: Markov reader;. Of course, since the compiler thinks you're declaring another variable called reader, it throws up this error. To create an instance of Markov, do this:
Markov m(reader);
This is an ambiguity in the grammar of C++ that is always taken as a declaration of a variable, rather than the construction of a temporary. In fact, you can have as many parentheses as you like around the variable name in your declaration: Markov (((((reader))))).
Markov(reader) is of course perfectly fine syntax for creating a temporary of type Markov, as long as it isn't in a statement that could be parsed as a declaration. For example, if it's in the middle of an expression, you'll be okay. In the contrived expression something += Markov(reader) - 6, it can't be interpreted as a declaration.
Likewise, if there is more than one argument being passed to the constructor, Markov(reader, writer), or if the single argument is not an identifier, Markov("foo"), it is not ambiguous.
If you're using a C++11 compiler, you can indeed create a temporary (although I see no reason to do it) that takes a single argument identifier using the new initialization syntax:
Markov{reader};
You may want to pass that fstream by reference.
Markov(fstream& inStream)
And while you're at it, if you're only using it for input services, use an ifstream& instead.