Can we call an object's constructor again after it is created?
#include <iostream>
struct A
{
A ( ) { std::cout << "A::A" << std::endl; }
~A ( ) { std::cout << "A::~A" << std::endl; }
};
int main( )
{
A a;
a.~A(); // OK
a.A::A(); // OK in Visual Studio 2005, 2008, 2010
return 0;
}
You shouldn't be able to call the constructor like this, as a member function call. The reason is (n3242, 12.1/2):
A constructor is used to initialize objects of its class type. Because constructors do not have names, they are
never found during name lookup; however an explicit type conversion using the functional notation (5.2.3)
will cause a constructor to be called to initialize an object.
If you really really want to call constructor on something what should be an object - and you shouldn't do it unless in very special cases - you can use placement new that calls the constructor:
new (&a) A();
Well, a.A() fails to compile because you simply cannot call a constructor in C++. (You can invoke it indirectly, however through several means.) For the same reason, I think a.A::A() should not compile.
Related
Have looked at various similar questions here but still can't figure out why the following code does not compile:
// these three are defined somewhere
class A;
std::unique_ptr<A> make_a();
void take_a(std::unique_ptr<A>&&);
int main(){
take_a(make_a()); // this fails
return 0;
}
According to this:
If the default deleter is used, T must be complete at the point in
code where the deleter is invoked, which happens in the destructor,
move assignment operator, and reset member function of
std::unique_ptr.
As far as I understand, none of these (destructor, move assignment operator, nor reset member function) happens in main.
So why does compiler needs the definition of A here?
Since main has a unique_ptr within its scope, realistically it would need to know how to delete the object it holds.
It's possible that take_a doesn't actually take ownership of the object, thus main would need to delete.
main gets a temporary unique_ptr from make_a(), let's call it X. It then passes an rvalue reference to X to take_a. It still has the destroy X. Hence, it has to call the destructor after take_a, even though X would typically be empty at that point.
We need class A description (at least constructor and destructor) in order to create and move std::unique_ptr<A> objects; take_a(make_a()) is creating such object because make_a() is pass-by-value. It first creates a new unique_ptr<A> object, initialize it (using default constructor), and then update its value and returns this new object. Here the default constructor/destructor is being used, which the compiler is unable to find.
#include <bits/stdc++.h>
class A {
public: A() {}
public: ~A() {}
};
std::unique_ptr<A> make_a() {
std::cout << "make";
std::unique_ptr <A> tt = nullptr;
return tt;
}
void take_a(std::unique_ptr<A>&&) {
std::cout << "take";
}
int main(){
take_a(make_a()); // this works now
return 0;
}
Edit: Forgot to add the link. Works the other way too.
The following code works OK:
#include <iostream>
using namespace std;
struct oops
{
~oops()
{
cout << " oops! " << endl;
}
};
struct sample
{
oops* x = nullptr;
sample(oops* p) : x(p)
{
cout << "sample: " << p << endl;
}
~sample()
{
delete x;
cout << "destroy sample " << endl;
}
sample(const sample&)
{
cout << "copy sample " << endl;
}
sample(sample&&)
{
cout << "move sample " << endl;
}
};
int main()
{
sample s = new oops;
return 0;
}
Result:
sample: 0x1470c20
oops!
destroy sample
It clearly shows that neither the move nor copy constructor was called.
When these constructors are deleted,
sample(const sample&) = delete;
sample(sample&&) = delete;
gcc gives a compile error:
bpp.cpp: In function ‘int main()’:
bpp.cpp:29:17: error: use of deleted function ‘sample::sample(sample&&)’
sample s = new oops;
^
bpp.cpp:24:2: note: declared here
sample(sample&&) = delete;
^
bpp.cpp:14:2: note: after user-defined conversion: sample::sample(oops*)
sample(oops* p) : x(p)
^
Does this have anything to do with -fno-elide-constructors?
How can I compile it without defining these constructors or using an explicit constructor?
Edit:
My GCC verison is 5.4.0. The command is:
g++ bpp.cpp -std=c++17
sample s = new oops;
This is a form of copy initialization. For a compiler to resolve it until C++17, a copy or move constructor must exist. However, a compiler is free to elide its call due to optimizations (with GCC and -fno-elide-constructors, the move constructor is called).
Since C++17, neither of these constructors is required: https://wandbox.org/permlink/3V8glnpqF5QxljJl.
How can I compile it without defining these constructors or using explicit constructor?
Very simply, avoid copy initialization and use direct initialization instead:
sample s { new oops };
Or, use C++17.
Why does this fail to compile?
This line of code:
sample s = new oops;
is equivalent to writing:
sample s = sample(new oops);
In C++11 and C++14, this implicitly calls the move constructor (or the copy constructor, if no move constructor is available). Because compilers are allowed to elide copies and moves, the actual move is elided, and it doesn't show anything when the move constructor is called. Even though the actual move is elided, programs aren't allowed to refer to deleted functions even implicitly, so there's a compiler error.
You can fix this by changing the initialization to either
sample s { new oops };
or
sample s ( new oops );
or, if you really wanna use =, you can take advantage of temporary lifetime extension to write
// s won't get destroyed until the end of the scope
// it's safe to use s after this statement
sample&& s = new oops;
What does C++17 change?
C++17 made some changes to the set of value categories objects fall in. In C++17, sample(new oops) becomes a prvalue, and the c++17 standard mandates that compilers are required to yeet prvalues into place without copying it or moving them. This is done through a combination of dark magic and sorcery.
This means that
sample s = new oops;
is legal in c++17.
Why does it still fail to compile when you add -std=c++17?
This code should compile under C++17, and the error you're getting occurs because gcc 6.3 and earlier don't implement that part of the c++17 standard. This issue was fixed in gcc 7.1 and the code will compile as expected.
For some educational reason I managed to stop others from taking the address of my class objects through overloading the reference operator & as a deleted member function or as a private method. But C++11 presents a new templated-function std::addressof which returns the address of an object. So I want also to disable it, however I'm stuck in half-solution. Here is my code try:
#include "stdafx.h"
#include <memory>
class Foo {
public:
Foo* operator&() = delete; // declared deleted so no one can take my address
friend Foo* addressof(Foo&) = delete; // ok here.
private:
// Foo* operator&() { return nullptr; } // Or I can declare it private which conforms to older versions of C++.
};
int main() {
Foo f{};
// std::cout << &f << std::endl;
// std::cout << addressof(f) << std::endl; // ok
std::cout << std::addressof(f) << std::endl;// Why I can't stop `std::addressof()`?
std::cout << std::endl;
}
As you can see if I call addressof which is a friend template function to my class then it works fine. But if someone calls std::addressof on my class object the compiler doesn't prevent him.
I need some way to stop std::addressof to not be called on my objects.
Thank you guys.
No.
The whole point of std::addressof is to allow people to find the address of the object when the author has tried to make this difficult/obfuscated/awkward.
There is no way, provided by the language, to disable or inhibit it. This is a feature.
Speaking practically, you could possibly fake it by specialising std::addressof for your type if you don't mind your program having undefined behaviour as a result! (Seriously, don't do this…).
I met one interesting compiling error when testing one small example:
#include <iostream>
using namespace std;
class A
{
public:
A() { cout <<"A created." <<endl; }
A(A& a) { cout <<"A created by copy constructor." <<endl; }
~A() { cout <<"A destoryed." <<endl; }
};
A CreateObject()
{
A obj;
return obj;
}
int main()
{
A a;
A b;
b= CreateObject();
return 0;
}
it's simple and may not have any issues at all. however, it prompted in compiling:
copy_constructor.cpp: In function ‘int main()’:
copy_constructor.cpp:23: error: no matching function for call to ‘A::A(A)’
copy_constructor.cpp:9: note: candidates are: A::A(A&)
it seems that the program tried to call copy constructor when compiling "b= CreateObject();" but there is no matching copy constructor. this should not happen because it just one assignment statement, is there any difference between constructor and normal function in compiling optimization ?
A(A& a) { cout <<"A created by copy constructor." <<endl; }
...
b = CreateObject();
This is invalid according to C++03 standard.
In C++03, b = CreateObject() may actually expand to b = A(CreateObject());. This has only been "fixed" in later versions of C++, where the creation of the temporary copy is now prohibited.
CreateObject() returns a r-hand value which can only be consumed by copy constructor with a A(const A& a) signature. Without the const modifier, it's only applicable to l-hand values.
E.g. b = a would still have been valid with that signature and the expansion, because you would be allowed to modify a inside the constructor.
This is still replicable setting clang++ to C++98 standard: http://coliru.stacked-crooked.com/a/50c25c469420ab0f
Older versions of Visual-C++ exhibit the precise error shown by the OP.
g++ fails to validate this correctly, even when explictly specifying C++98.
See also https://stackoverflow.com/a/13898867/2879325
The code you've posted compiles just fine. You should however change your copy constructor from A(A&) to A(const A&).
After trying to write an example regarding move constructors, I ran into the following code:
#include <utility>
#include <iostream>
using namespace std;
class Data
{
public:
Data()
: x (3)
{
cout << "Data()" << endl;
}
Data(Data&&)
: x(4)
{
cout << "Data(&&)" << endl;
}
int x;
};
int main()
{
Data a;
Data b (std::move(a));
cout << b.x << endl;
return 0;
}
Why is the move constructor not called here?
The program prints:
Data()
3
What I'm finding even weirder is that by adding a copy constructor, suddenly, it does call the move constructor...
Data(const Data&)
: x(2)
{
cout << "Data(copy)" << endl;
}
And now it will print
Data(&&)
4
P.S I'm using gcc 4.4.5
Well, your code works properly for me. See this sample.
Output:
Data()
Data(&&)
4
As standard says:
The move constructor is called whenever an object is initialized from
xvalue of the same type, which includes
initialization, T a = std::move(b); or T a(std::move(b));, where b is of type T
function argument passing: f(std::move(a));, where a is of type T and f is void f(T t)
function return: return a; inside a function such as T f(), where a is of type T which has a move constructor.
And
std::move obtains an rvalue reference to its argument and converts it to an xvalue.
I see no reason for behavior you describe. Perhaps there is something wrong with your compiler?
EDIT
It seems, that it is indeed the fault of the compiler. Definition of move functions was described in proposal N3053 ("Defining Move Special Member Functions"). As we can see in table on this page:
Your code is well-formed and should call the move constructor. However, gcc 4.4, does not support defining move functions as stated here.
You do want to consider to update your compiler.