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.
Related
In the first time,the code looks like below:
#include "stdafx.h"
#include<iostream>
using namespace std;
class Test{
public:
explicit Test(int);
~Test();
//Test(Test&);
int varInt;
};
Test::Test(int temp){
varInt = temp;
cout << "call Test::constructor\n";
}
Test::~Test(){
cout << "call Test::destructor\n";
}
/*Test::Test(Test&temp){
varInt = temp.varInt;
cout << "call Test::copy constructor\n";
}*/
void func(Test temp){
cout << "call func\n";
}
int _tmain(int argc, _TCHAR* argv[])
{
func(Test(1));
return 0;
}
output:
call Test::constructor
call func
call Test::destructor
call Test::destructor
This confuses me,cause there's only one object that was created(as the argument of func),but two destructors were called after the function ends.
I started to wonder,is this because the default copy constructor was called?So I wrote the definition of copy constructor,which made things just more strange.
After I add the Commented-Out Code as you can see above,namely the definition of copy constructor,into the class,the output became like this:
output:
call Test::constructor
call func
call Test::destructor
Things became just right now.
Can someone explain this phenomenon to me?Thank u very much.
Your interpretation of your original code (that the implicitly-declared copy constructor is being called) is correct.
Depending on the version of the standard that your compiler is implementing, it may actually be using the implicitly-declared move constructor instead. But this amounts to the same thing.
Your modified code (where you've explicitly provided a copy constructor) happens to be triggering the copy elision optimization, where the compiler just constructs the object in the desired location to begin with. This is one of the few situations where the standard specifically allows an optimization even though it affects the observable behavior of the program (since you can tell whether your copy constructor was called).
Nothing about your modified code requires copy elision, and nothing about your original code forbids it; the two versions just happen to differ in whether they trigger the optimization in your compiler under your current settings.
Note: the situation here changes a bit in C++17, where this optimization does become mandatory in some cases. See my above link for details.
Edited to add: Incidentally, in your version with an explicit copy constructor, your constructor is unusual in taking a non-constant reference. This actually means that it can't be used anyway, since a non-constant reference can't bind to the temporary Test(1). I think this oddness may have to do with why your compiler is performing copy elision. If you change the constructor to take a constant reference, as the implicitly-declared copy constructor would, you may see the behavior you were expecting, with your explicit copy constructor being called and the destructor being called twice. (But that's just speculation on my part; you'll have to try it and see!)
You have two objects of class Test. Since you pass arguments by value, one is constructed explicitly in the main function, another one is constructed with default copy constructor, as your copy constructor is commented out. Both objects get destructed. One on the exit from func(), another at the exit from main(). Hence two destructor calls.
I just upgrade from Visual Studio 2013 to 2015, and I'm running into a bunch of issues with things that used to work in 2013, but which do not in 2015.
For example, here's one that has me stumped. I created a test-case out of the original code.
Basically, the code runs some operations in a thread, via std::async(). Within the thread, exceptions might be thrown (A), which should be placed in the future object returned by std::async(). The weird thing is that in (B), the destructor of Ex is called, but the object is still thrown aftewards. In the try-block, when the ex (D) variable leaves the score, if 'mInts' vector (X) is a member, the program would crash. If I leave 'mInts' commented out, as below, I still get weird behavior. For example, this is what's printed with the code below: notice how the constructor is called one, but the destructor is called 4 times:
Output:
constructor
destructor
before exception
after exception
destructor
has exception
destructor
destructor
Code:
using FutureList = std::vector<std::future<void>>;
struct Ex {
Ex() {
std::cout << "constructor\n";
}
Ex(const Ex&) = delete;
Ex(Ex&&) {
std::cout << "move constructor";
}
~Ex() {
std::cout << "destructor\n";
}
void operator=(const Ex&) {
std::cout << "assign\n";
}
// std::vector<int> mInts; (X)
};
TEST(Explore, Test1) {
FutureList futures;
futures.push_back(
std::async(std::launch::async, []() {
throw Ex(); // (A)
}));
std::exception_ptr ex;
for (auto& i : futures) {
try {
i.get(); // (B)
std::cout << "Doesn't get here.\n";
}
catch (...) { // (C)
std::cout << "before exception\n";
ex = std::current_exception(); // (D)
std::cout << "after exception\n";
}
}
if (ex) {
std::cout << "has exception\n";
}
}
Actually, MSVC doesn't call the copy constructor in your example. There's no code to call; the function is deleted. It does something worse: it treats the class as being trivially copyable and does a memcpy on the object. That's the reason for the crash when you have a member of type std::vector<int>.
The problem is not directly related to std::async. It's caused by the implementation of std::exception_ptr. The shared state of a std::future uses an exception_ptr to store an exception, so using a future in the context of exceptions will trigger the problem. The issue can otherwise be reproduced when using only std::current_exception(), which involves a copy in VC 14's standard library implementation (the Standard allows that).
The problem is with the implementation of __ExceptionPtr::_CallCopyCtor in crt/src/stl/excptptr.cpp. It essentially does a test that goes like "Is there a copy constructor? No? Great, we can do a memcpy then!".
Another problem is that the test ignores access specifiers. If you provide a copy constructor but make it private, it will be called.
The test is done at runtime, so no chance for a compile-time error, and, unfortunately, that's the only way to do it: there is no general compile-time test that will tell what type of exception object an std::exception_ptr will point to in all cases.
The proposed resolution for Core issue 1863 aims to avoid this problem by requiring that
[...] the constructor selected for a copy-initialization considering the thrown object as an lvalue shall be non-deleted and accessible. [...]
The issue is in Ready status, which is one step away from adoption.
So, while this is definitely a problem with MSVC, it's also related to an open issue in the Standard. For now, it looks like a good idea to provide a copy constructor for exception objects, even if the Standard doesn't require it (yet).
Update: The resolution for issue 1863 has been adopted into the N4567 working draft, so compilers implementing the change are required to reject the code if a suitable constructor is not available.
It seems that MSVC 2015 still calls the copy constructor, even though it's marked deleted. To get around this issue, I defined the copy constructor.
The issue with the printout was because there was no printing in the copy constructor. I added some, and the constructor/destructor count matched.
Still, MSVC 2015 shouldn't be calling the copy-constructor if it's marked deleted. If it must be called, then it should issue an error.
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.
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.
I was reading the difference between direct-initialization and copy-initialization (§8.5/12):
T x(a); //direct-initialization
T y = a; //copy-initialization
What I understand from reading about copy-initialization is that it needs accessible & non-explicit copy-constructor, or else the program wouldn't compile. I verified it by writing the following code:
struct A
{
int i;
A(int i) : i(i) { std::cout << " A(int i)" << std::endl; }
private:
A(const A &a) { std::cout << " A(const A &)" << std::endl; }
};
int main() {
A a = 10; //error - copy-ctor is private!
}
GCC gives an error (ideone) saying:
prog.cpp:8: error: ‘A::A(const A&)’ is private
So far everything is fine, reaffirming what Herb Sutter says,
Copy initialization means the object is initialized using the copy constructor, after first calling a user-defined conversion if necessary, and is equivalent to the form "T t = u;":
After that I made the copy-ctor accessible by commenting the private keyword. Now, naturally I would expect the following to get printed:
A(const A&)
But to my surprise, it prints this instead (ideone):
A(int i)
Why?
Alright, I understand that first a temporary object of type A is created out of 10 which is int type, by using A(int i), applying the conversion rule as its needed here (§8.5/14), and then it was supposed to call copy-ctor to initialize a. But it didn't. Why?
If an implementation is permitted to eliminate the need to call copy-constructor (§8.5/14), then why is it not accepting the code when the copy-constructor is declared private? After all, its not calling it. Its like a spoiled kid who first irritatingly asks for a specific toy, and when you give him one, the specific one, he throws it away, behind your back. :|
Could this behavior be dangerous? I mean, I might do some other useful thing in the copy-ctor, but if it doesn't call it, then does it not alter the behavior of the program?
Are you asking why the compiler does the access check? 12.8/14 in C++03:
A program is ill-formed if the copy
constructor or the copy assignment
operator for an object is implicitly
used and the special member function
is not accessible
When the implementation "omits the copy construction" (permitted by 12.8/15), I don't believe this means that the copy ctor is no longer "implicitly used", it just isn't executed.
Or are you asking why the standard says that? If copy elision were an exception to this rule about the access check, your program would be well-formed in implementations that successfully perform the elision, but ill-formed in implementations that don't.
I'm pretty sure the authors would consider this a Bad Thing. Certainly it's easier to write portable code this way -- the compiler tells you if you write code that attempts to copy a non-copyable object, even if the copy happens to be elided in your implementation. I suspect that it could also inconvenience implementers to figure out whether the optimization will be successful before checking access (or to defer the access check until after the optimization is attempted), although I have no idea whether that warranted consideration.
Could this behavior be dangerous? I
mean, I might do some other useful
thing in the copy-ctor, but if it
doesn't call it, then does it not
alter the behavior of the program?
Of course it could be dangerous - side-effects in copy constructors occur if and only if the object is actually copied, and you should design them accordingly: the standard says copies can be elided, so don't put code in a copy constructor unless you're happy for it to be elided under the conditions defined in 12.8/15:
MyObject(const MyObject &other) {
std::cout << "copy " << (void*)(&other) << " to " << (void*)this << "\n"; // OK
std::cout << "object returned from function\n"; // dangerous: if the copy is
// elided then an object will be returned but you won't see the message.
}
C++ explicitly allows several optimizations involving the copy constructor that actually change the semantics of the program. (This is in contrast with most optimizations, which do not affect the semantics of the program). In particular, there are several cases where the compiler is allowed to re-use an existing object, rather than copying one, if it knows that the existing object will become unreachable. This (copy construction) is one such case; another similar case is the "return value optimization" (RVO), where if you declare the variable that holds the return value of a function, then C++ can choose to allocate that on the frame of the caller, so that it doesn't need to copy it back to the caller when the function completes.
In general, in C++, you are playing with fire if you define a copy constructor that has side effects or does anything other than just copying.
In any compiler, syntax [and semantic] analysis process are done prior to the code optimization process.
The code must be syntactically valid otherwise it won't even compile. Its only in the later phase (i.e code optimization) that the compiler decides to elide the temporary that it creates.
So you need an accessible copy c-tor.
Here you can find this (with your comment ;)):
[the standard] also says that the temporary copy
can be elided, but the semantic
constraints (eg. accessibility) of the
copy constructor still have to be
checked.
RVO and NRVO, buddy. Perfectly good case of copy ellision.
This is an optimization by the compiler.
In evaluating: A a = 10; instead of:
first constructing a temporary object through A(int);
constructing a through the copy constructor and passing in the temporary;
the compiler will simply construct a using A(int).