Does variables creation depend on the scope? - c++

void someFunc()
{
int local0 = 0;
//some code
{
int local1 = 0;
//some code
}
int local2 = 0;
}
All three local variables will be created(allocated on the stack) at the moment of entering someFunc? Or local0 will be created first, then local1, then local1 will be deleted, and then local2 created and on the exit local0 and local2 will be deleted?

So, this question is hard to answer in the abstract. The compiler is free to reorder your code, so long as it is equivalent to the code as written if executed sequentially. That is to say, what assembly is generated is up to the compiler.
With this specific code, and this specific code alone, a compiler performing any optimization is highly likely to realize this function is a no-op, and elide it (godbolt).
That said, as general guidance, C++ does not perform mandatory variable hoisting (as with JS, see here). That is, it is at best undefined behavior (at worst, errant syntax) to use the names of variables before they are declared.
Edit: As Deduplicator mentioned in the comments, the as-if rule formalizes how compilers can transform code. It specifies that code changes which do not affect the "observable behavior" of the program are allowed. I like John Regehr's definition of observable behavior (here), though it is a little tautological:
Observable behaviors are those that are side effecting.

C++ is defined in terms of an abstract machine. In the abstract machine the operations happen in this order:
local0 is created
local1 is created
local1 is destroyed
local2 is created
The requirements on the real machine are only that it must produce the same output that the abstract machine would . There are no requirements about how it goes about producing that output.
For this particular program the real machine might not create any of the variables since they are unused and removing them doesn't affect the output.

It's easier to get a handle on this if you use variables whose construction and destruction have side-effects. Then you can see them coming and going.
So, given this:
class Foo
{
int m_i;
public:
Foo (int i) : m_i (i) { std::cout << "Foo constructor #" << i << "\n"; }
~Foo () { std::cout << "Foo destructor #" << m_i << "\n"; }
};
We can then rewrite your example as:
void someFunc()
{
Foo local0 (0);
{
Foo local1 (1);
}
Foo local2 (2);
}
Which gives the output:
Foo constructor #0
Foo constructor #1
Foo destructor #1
Foo constructor #2
Foo destructor #2
Foo destructor #0
Which in turn makes everything clear.
As others have mentioned, if the variables are primitive types (and don't depend on each other) then the compiler is free to reorder the statements in order to generate faster code.

Related

What is the difference between Rust's Drop and C++'s destructor?

While reading about the Drop trait, I found a lot of similarities between the drop method of Rust and the destructor in a C++. What is the difference between the two?
In practice, there is no appreciable difference. Both are used to clean up the resources of a type when appropriate.
Resources will be cleaned up irrespective of implementation of the Drop trait, won't they?
Yes. The compiler essentially automatically implements Drop for any type where the programmer does not. This automatic implementation simply calls drop for each member variable in turn.
If you allocate a resource that Rust doesn't know about, such as allocating memory directly from an allocator, Rust won't know that the returned value needs to be dropped or how to do so. That's when you implement Drop directly.
See also:
Running Code on Cleanup with the Drop Trait
The only differences I know of are related to features that C++ has but Rust doesn't. Other folks have mentioned inheritance in the comments above, but a simpler example might be types with multiple constructors. In Rust, depending on what we mean by "constructor", we could say that every type has exactly one constructor (the syntax where you name the type and initialize all its fields). But in C++ a type can have multiple constructors, and importantly, one constructor can delegate to another. Here's a quick example:
class foo {
public:
// the inner constructor
foo(bool throw_in_inner_ctor) {
if (throw_in_inner_ctor) {
throw runtime_error("throw in inner ctor");
}
}
// the outer constructor, which delegates to the inner one
foo(bool throw_in_inner_ctor, bool throw_in_outer_ctor)
: foo(throw_in_inner_ctor) {
if (throw_in_outer_ctor) {
throw runtime_error("throw in outer ctor");
}
}
// the destructor
~foo() {
cout << "foo dtor\n";
}
};
int main() {
try {
cout << "construct a foo that throws in its inner ctor\n";
foo(true, false);
} catch (runtime_error) {}
try {
cout << "construct a foo that throws in its outer ctor\n";
foo(false, true);
} catch (runtime_error) {}
}
This prints:
construct a foo that throws in its inner ctor
construct a foo that throws in its outer ctor
foo dtor
What we're seeing here is that when the inner constructor throws, the destructor of foo doesn't get invoked. But when the outer constructor throws, it does. The rule is that our foo will get destructed if any constructor returns without an exception, regardless of what other delegating constructors might do. Rust has no equivalent to this rule, both because Rust doesn't have delegating constructors, and because constructors in Rust (if you want to call them that) cannot run arbitrary code and cannot fail.

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.

Are objects created before setjmp destructed?

In jpeglib, one has to use setjmp/longjmp to implement custom error handling.
There are lots of resources where it is said that setjmp/longjmp do not play well with c++ (for example answers in this question tell they do go along with RAII), but the answers to this question say that the destructor is called.
I have this example (taken from here and modified a bit):
#include <iostream>
#include <csetjmp>
std::jmp_buf jump_buffer;
struct A
{
A(){std::cout<<"A()"<<std::endl;}
~A(){std::cout<<"~A()"<<std::endl;}
};
void a(int count)
{
std::cout << "a(" << count << ") called\n";
std::longjmp(jump_buffer, count+1); // setjump() will return count+1
}
int main()
{
// is this object safely destroyed?
A obj;
int count = setjmp(jump_buffer);
if (count != 9) {
a(count);
}
}
In this example, the destructor is called (as I expected), but is it the standard behaviour? Or is it compiler's extension, or simple UB?
The output:
A()
a(0) called
a(1) called
a(2) called
a(3) called
a(4) called
a(5) called
a(6) called
a(7) called
a(8) called
~A()
It can be undefined behaviour depending on whether or not destructors would be called were an exception to execute the same transfer of control. In C++03. From section 18.7 Other runtime support, paragraph 4:
The function signature longjmp(jmp_buf jbuf, int val) has more restricted behavior in this International Standard. If any automatic objects would be destroyed by a thrown exception transferring control to another (destination) point in the program, then a call to longjmp(jbuf, val) at the throw point that transfers control to the same (destination) point has undefined behavior.
There's similar language in c++11:
The function signature longjmp(jmp_buf jbuf, int val) has more restricted behavior in this International Standard. A setjmp/longjmp call pair has undefined behavior if replacing the setjmp and longjmp by catch and throw would invoke any non-trivial destructors for any automatic objects.
However, there appear to be no destructors that are called in transition for this particular piece of code, so I believe it's safe.
Now, if you were to change the code to move the creation to after the setjmp, that becomes undefined behaviour. In my setup (gcc 4.4.5 under Debian), the following code (with everything else identical to your question):
int main() {
int count = setjmp (jump_buffer);
A obj;
if (count != 4) a (count);
}
results in the output:
A()
a(0) called
A()
a(1) called
A()
a(2) called
A()
a(3) called
A()
~A()
and you can see the destructor is not being called as part of the jump although, being undefined, it may be on some systems.
The bottom line is, you shouldn't be jumping from region A to region B where the equivalent throw/catch would properly destruct an object, because there's no guarantee the longjmp will call the destructor.
Actually, there are some who would say you shouldn't use setjmp/longjmp in C++ at all, and I tend to lean that way myself. I have a hard time seeing a need for that even in C.
I think I used it once in my entire career (and that's a long career), to implement co-operative threading in Turbo C under MS-DOS. I can't think of one other time I've ever used it. Not to say there aren't any uses, but they'd be pretty rare.

Strange C++ behaviour involving multiple calls to destructor

I'm running the following code in Dev Studio 2010:
struct Foo
{
Foo() {cout << "Foo()" << endl;}
~Foo() {cout << "~Foo()" << endl;}
void operator ()(const int &) const {}
};
int bar[] = {0};
for_each(begin(bar), end(bar), Foo());
The output is not what I expected, and is the same in both debug and release regardless of the contents of the "bar" array:
Foo()
~Foo()
~Foo()
~Foo()
I've looked at the outputted assembly and I can't for the life of me understand why the compiler is generating extra calls to the destructor. Can anyone explain to me exactly what's going on?
This is because nameless temporary objects are being created and destroyed during the course of the program.
Usually, the standard does not provide any guarantees w.r.t creation of temporary objects while using Standard Library containers and Algorithms. Implementations are allowed to create temporary objects if they desire so(for good performance or whatever).
Note that You should follow the Rule of Three in c++03 and Rule of Five in c++11 to avoid any problems due to temporary object creation.
For each is a templated function, and in the case that you're using it, the parameter Foo will be typed as Foo, not as Foo& Foo*.
That means that the Foo object will be copied.
Why is it being copied twice? Once into the function, and once out. for_each will copy the anonymous Foo when it takes in the Foo arguement and then it will return a copy of it because its return type is also Foo.
To elaborate a tiny bit on what Als was saying: the copy constructor is being used.
To have it not copy, you could explicitly type it as a reference (though, as Als said, this would be implementation specific as theoretically for_each can make explicit copies if it wants):
for_each<Foo&>(..., ..., ...)

How to check for C++ copy ellision

I ran across this article on copy ellision in C++ and I've seen comments about it in the boost library. This is appealing, as I prefer my functions to look like
verylargereturntype DoSomething(...)
rather than
void DoSomething(..., verylargereturntype& retval)
So, I have two questions about this
Google has virtually no documentation on this at all, how real is this?
How can I check that this optimization is actually occuring? I assume it involves looking at the assembly, but lets just say that isn't my strong suit. If anyone can give a very basic example as to what successful ellision looks like, that would be very useful
I won't be using copy ellision just to prettify things, but if I can be guaranteed that it works, it sounds pretty useful.
I think this is a very commonly applied optimization because:
it's not difficult for the compiler to do
it can be a huge gain
it's an area of C++ that was a commonly critiqued before the optimization became common
If you're just curious, put a debug printf() in your copy constructor:
class foo {
public:
foo(): x(0) {};
foo(int x_) : x( x_) {};
foo( foo const& other) : x( other.x) {
printf( "copied a foo\n");
};
static foo foobar() {
foo tmp( 2);
return tmp;
}
private:
int x;
};
int main()
{
foo myFoo;
myFoo = foo::foobar();
return 0;
}
Prints out "copied a foo" when I run an unoptimmized build, but nothing when I build optimized.
From your cited article:
Although copy elision is never required by the standard, recent versions of every compiler I’ve tested do perform these optimizations today. But even if you don’t feel comfortable returning heavyweight objects by value, copy elision should still change the way you write code.
It is better known as Return Value Optimization.
The only way to know for sure is to look at the assembly, but you're asking the wrong question. You don't need to know if the compiler is eliding the copy unless it matters to the program timing. A profiler should easily tell you if you're spending too much time in the copy constructor.
The poor man's way to figure it out is to put a static counter in the copy constructor and try both forms of your function. If the counts are the same, you've successfully avoided the copy.
Google "Named Return Value Optimization" and "Return Value Optimization" instead. Modern compilers will in fact not perform the copy in many cases.
You can check if it's occurring by returning a type with side effects -- such as printing a message. Wikipedia has some good examples of where program output changes when RVO and/or NRVO is in effect.
Example of what it looks like:
#include <iostream>
struct Foo {
int a;
Foo(int a) : a(a) {}
Foo(const Foo &rhs) : a(rhs.a) { std::cout << "copying\n"; }
};
int main() {
Foo f = Foo(1);
}
If you see no output, then copy elision has taken place. That's elision of a copy from an initializer. The other legal case of copy elision is a return value, and is tested by:
Foo getFoo() {
return Foo(1);
}
int main() {
Foo f = getFoo();
}
or more excitingly for a named return value:
Foo getFoo() {
Foo f(1);
return f;
}
int main() {
Foo f = getFoo();
}
g++ performs all those elisions for me with no optimisation flags, but you can't really know whether more complex code will outwit the compiler.
Note that copy elision doesn't help with assignment, so the following will always result in a call to operator= if that operator prints anything:
Foo f(1);
f = getFoo();
Returning by value therefore can still result in "a copy", even if copy constructor elision is performed. So for chunking great classes it's still a performance consideration at the design stage. You don't want to write your code such that fixing it later will be a big deal if it turns out your app spends a significant proportion of its time in copying that could have been avoided.
To answer question 2, you could write a demo program where you write a class DemoReturnType; which has instrumented constructors and destructors which just write to cout when they are called. This should give you enough information about what your compiler is capable of.
Rvalue references solve this problem in C++0x. Whether or not you can obtain an rvalue-enabled compiler is another question - last time I checked only Visual Studio 2010 supports it.