is pointed static_cast valid to avoid copying? - c++

update:
class foo {
public:
foo() : x_(0) { std::cout << "foo constructor\n"; }
foo(foo& c) : x_(c.x_) { std::cout << "foo copy- constructor\n"; }
foo& operator=(foo const& c) {
std::cout << "foo operator=\n";
x_ = c.x_;
return *this;
}
protected:
int x_;
};
class bar : public foo {
public:
bar(int x) { foo::x_ = x; std::cout << "bar constructor\n"; }
bar(bar& c) { std::cout << "bar copy- constructor\n"; }
bar& operator=(bar const& c) {
foo::operator=(c);
std::cout << "bar operator=\n";
return *this;
}
};
int main() {
foo f;
bar b(123);
std::cout << "f = *static_cast<foo*>(&b);\n";
f = *static_cast<foo*>(&b); // no copy constructor is called
std::cout << "f = static_cast<foo>(b);\n";
f = static_cast<foo>(b); // copy constructor and assignment is called
}
output:
g++ -std=c++11 -Wall -pedantic -o main main.cpp && ./main
foo constructor
foo constructor
bar constructor
f = *static_cast<foo*>(&b);
foo operator=
f = static_cast<foo>(b);
foo copy- constructor
foo operator=
Is there an disatvantage of doing the static_cast like *static_cast<foo*>(&b); which is not calling the copy constructor as you can see in the output. see working example here.

In the now completely different question:
f = *static_cast<foo*>(&b);
is equivalent to
f = b;
which calls foo& operator=(foo const& c) with no additional temporaries. However,
f = static_cast<foo>(b);
is equivalent to:
f = foo(b);
or
{
foo temporary(b); // calls foo(foo const& );
f = temporary; // calls foo& operator=(foo const& );
}
which does create a temporary. Definitely prefer to do just:
f = b;

Given the now-functioning code, this line:
base b = *static_cast<base*>(&d);
Is exactly equivalent to these two:
base b = static_cast<b&>(d);
base b = d;
In every case, we're calling base(base const&) with no temporary copies. d is just taken as a const base&.
There is a downside of doing this construction (outside of static_cast just adding noise), which is that b is just a base object. It is not of type derived. So if you had some virtual function base::foo that derived provided an override of, b.foo() would call base::foo. This is known as slicing. If you want to mantain the derived-ness through the assignment, you have to keep a reference or pointer:
base& b = d;
base* b = &d;

Is there an disatvantage of doing the static_cast like *static_cast<foo*>(&b);
Yes. It's unnecessary noise. Just do this:
f = b;
It has the exact same effect.

Related

Reason of additional destructor call?

Given is the following simple class:
#include <iostream>
class Foo{
int a, b;
public:
Foo(int _a = 0, int _b = 0) : a(_a), b(_b) {
std::cout << "Foo(int, int)" << "\n";
}
Foo(const Foo& foo) : a(foo.a), b(foo.b) {
std::cout << "Foo(const Foo&)" << "\n";
}
Foo& operator=(const Foo& other) {
std::cout << "operator=(const Foo&)" << "\n";
if(this != &other){
a = other.a;
b = other.b;
}
return *this;
}
~Foo() {
std::cout << "~Foo()" << "\n";
}
Foo operator+(const Foo& other){
std::cout << "foo.operator+(const Foo&)" << "\n";
return Foo(a + other.a, b + other.b);
}
};
and the main:
int main(){
Foo f1, f2(1, 2), f3;
std::cout << "-----------" << "\n";
f3 = f1 + f2; // (*)
std::cout << "-----------" << "\n";
return 0;
}
I compiled with -std=c++11 and for demonstration purposes also with the -fno-elide-constructors flag. The output reads as:
Foo(int, int)
Foo(int, int)
Foo(int, int)
-----------
foo.operator+(const Foo&) // (1)
Foo(int, int) // (2)
Foo(const Foo&) // (3)
~Foo() // (4)
operator=(const Foo&) // (5)
~Foo() // (6)
-----------
~Foo()
~Foo()
~Foo()
As far as I understand it correctly, the following happens for the line f3 = f1 + f2; (*):
Obviously, f1.operator+(f2) is called.
A new (temporary) object is created. Let's denote it by T.
Since the operator+() function does not return a reference, we call to copy constructor in order to construct a copy T2 of T. We return T2.
The destructor is called in order to delete the temporary object T.
We call the copy assignment operator to assign all members of T2 to f3.
My question: I don't really see what's the purpose of (6). Why is there an additional call to the destructor, i.e. what am I missing here?
what am I missing here?
The destruction of T2.
There are 3+2 constructors called, there must be 3+2 destructors called too!

copy constructor, operator= in a child class

I want to make an operator= and copy constructor, to be called in the inherited class.
For normal objects, it works fine, but when I'm trying to call, for example, operator= with a pointer, it is just copying the object address.
So my question is, how can I call those methods with pointers?
#include <iostream>
// base class
class a {
public:
//constructors
a(): x(0), y(1), z(0){ std::cout << "no parameter constructor A\n"; }
a(int a, int b, int c) :x(a), y(b), z(c){ std::cout << "parameter constructor A\n"; }
a(const a& ob):x(ob.x), y(ob.y), z(ob.z)
{
std::cout << "copy constructor A\n";
}
//operator
a& operator=(const a& obj)
{
if (this != &obj)
{
x = obj.x;
y = obj.y;
z = obj.z;
}
std::cout << "operator = A\n";
return *this;
}
protected:
int x, y, z;
};
//child class
class b : public a
{
public:
//constructors
b() : p(0){ std::cout << "no parameter constructor B\n"; }
b(int X, int Y, int Z, int B) : a(X, Y, Z), p(B) { std::cout << "parameter constructor B\n"; }
b(const b& obj) :p(obj.p), a(obj)
{
std::cout << "copy constructor B\n";
}
//operator =
b& operator=(const b &obj)
{
if (this != &obj)
{
p = obj.p;
&a::operator=(obj);
}
std::cout << "operator = B\n";
return *this;
}
private:
int p;
};
int main()
{
b obj0(4, 8, 16, 32);
b obj1(obj0); // copy constructor
b obj2;
obj2 = obj1; // operator =
std::cout << std::endl << std::endl;
std::cout << "for pointers:\n\n";
a* obj3 = new b(4, 8, 16, 32);
a* obj4(obj3);
obj4 = obj3;
return 0;
}
One of the purposes of using pointers (or references) is to avoid needing to create a copy of the object. Passing a pointer to the object allows the receiver to refer to and manipulate on the original object.
If you wish the pointer to receive a new object, then you would use new.
When dealing with polymorphism as in your example, you would probably need a virtual method that creates a proper clone (sometimes called a deep copy).
class a {
//...
virtual a * clone () const = 0;
};
class b : public a {
//...
b * clone () const {
return new b(*this);
}
};
//...
a *obj4 = obj3->clone();
//...
We leverage that b * is a covariant return type for a *, so that b::clone() can return a b *, but a::clone() can use the b::clone() as an override and still return an a *.

arguments to tuple are copied instead of moved when returning the tuple from a function

I have a question about the following code. My compiler is MSVC++ 17 Visual studio version 15.3 with compiler option /std:c++14 (as opposed to /std:c++latest) running in release mode:
struct Bar
{
int a;
std::string b;
Bar() { std::cout << "default\n"; }
Bar(int a, const std::string& b) : a{ a }, b{ b } { std::cout << "direct\n"; }
Bar(int a, std::string&& b) : a{ a }, b{ std::move(b) } { std::cout << "direct move b\n"; }
Bar(const Bar& other) : a{ other.a }, b{ other.b } { std::cout << "const copy\n"; }
Bar(Bar&& other) : a{ std::move(other.a) }, b{ std::move(other.b) } { std::cout << "move\n"; }
Bar& operator=(const Bar& other)
{
a = other.a;
b = other.b;
std::cout << "const assign\n";
return *this;
}
Bar& operator=(Bar&& other)
{
a = std::move(other.a); //would this even be correct?
b = std::move(other.b);
std::cout << "move assign\n";
return *this;
}
};
std::tuple<Bar, Bar> foo()
{
std::string s = "dsdf";
return { { 1, s }, { 5, "asdf" } };
}
int main()
{
Bar a, b;
std::tie(a, b) = foo();
std::cout << a.a << a.b << std::endl;
std::cout << b.a << b.b;
}
The output is:
default
default
direct
direct move b
const copy <-- Why copy? Why not move>
const copy <-- Why copy? Why not move>
move assign
move assign
1dsdf
5asdf
If I change return { { 1, s }, { 5, "asdf" } }; to return { Bar{ 1, s }, Bar{ 5, "asdf" } }; the output changes to:
default
default
direct
direct move b
move
move
move assign
move assign
1dsdf
5asdf
Question: Why isn't a move performed in both cases? Why is the copy constructor called in the first case?
The simplest distillation of your question is why:
std::tuple<Bar> t{{5, "asdf"}};
prints
direct move b
const copy
but
std::tuple<Bar> u{Bar{5, "asdf"}};
prints
direct move b
move
To answer that question, we have to determine what those two declarations actually do. And in order to do that, we have to understand which of std::tuple's constructors get called. The relevant ones are (neither the explicitness and constexprness of each constructor is relevant, so I am omitting them for brevity):
tuple( const Types&... args ); // (2)
template< class... UTypes >
tuple( UTypes&&... args ); // (3)
Initializing with Bar{5, "asdf"} would invoke constructor (3) as the better match (both (2) and (3) are viable, but we get a less cv-qualified reference in (3)), which would forward from the UTypes into the tuple. This is why we end up with move.
But initializing with just {5, "asdf"}, this constructor isn't viable because braced-init-lists have no type that can be deduced. Hence our only option is (2), and we end up with a copy.
The only way to fix this would be to add non-template constructors that take rvalue references to each of the Types. But you would need 2^N-1 such constructors (all but the one that takes all const lvalue references - since that one could be deduced), so instead we end up with a design that works in all cases but is suboptimal. But since you could just specify the type you want on the call site, this isn't a huge defect.

Which constructor or assignment operator is getting called in this code?

The output is
Constructor called
20
When I am adding a copy-constructor, it is giving error "invalid initialization of non-const reference of type ‘Foo&’ from an rvalue of type ‘Foo’ "
#include <iostream>
using namespace std;
class Foo
{
int a;
public:
Foo(int a)
{
this->a =a;
cout<<"Constructor called\n";
}
void operator=(Foo f)
{
this->a = a;
cout<< "Assignment operator called";
}
void show()
{
cout<<this->a<<endl;
}
};
int main()
{
// your code goes here
Foo F1 = static_cast<Foo>(20);
F1.show();
return 0;
}
There is no assignment in the code you posted. This:
Foo F1 = static_cast<Foo>(20);
is alternate syntax for copy construction, and is an initialisation, not an assignment.
Your problem with the copy constructor is probably caused by you defining it as
Foo( Foo & f );
which prevents it from binding to temporary values. It should be:
Foo( const Foo & f );

Order of casting in C++

I would like to ask about casting in C++.
I heard that when casting is ambiguous compiler should return an error,
but, just for better understanding, I tested it and it didn't, moreover, it used functions in quite weird order. When:
A foo;
B bar = foo;
it used casting operator, but when I typed:
bar = static_cast<B>(foo);
it used single argument constructor.
Can anyone explain why it acts in this way?
The whole code which I used:
#include <iostream>
#include <typeinfo>
using namespace std;
class B;
class A {
public:
A() {}
A (const B& x);
A& operator= (const B& x);
operator B();
};
class B {
public:
B() {}
B (const A& x) {
cout << "constructor B" << endl;
}
B& operator= (const A& x) {
cout << "Assign B" << endl;
return *this;
}
operator A() {
cout << "Outer B" << endl;
return A();
}
};
A::A (const B& x) {
cout << "constructor A" << endl;
}
A& A::operator= (const B& x) {
cout << "Assign A" << endl;
return *this;
}
A::operator B() {
cout << "Outer A" << endl;
return B();
}
int main ()
{
A foo;
// First one
B bar = foo;
bar = foo;
foo = bar;
// Second one
bar = static_cast<B>(foo);
B bar2 = static_cast<B>(foo);
foo = static_cast<A>(bar);
B bar3 = foo;
A foo2 = bar3;
A foo3 = B();
foo3 = B();
return 0;
}
Edit:
My output:
Outer A
Assign B
Assign A
Copy constructor B
Copy constructor B
Copy constructor A
Outer A
Outer B
Outer B
Assign A
The reason your compiler does not complain about ambiguity is that your constructors and assignment operators take a const A/B&, but operator A() and operator B() are not declared const. For the conversion of non-const objects, the compiler therefore prefers operator A/B().
I think that the rest can be explained with the rules of static_cast conversion, which in your code amounts to behavior as in direct initialization, and overload resolution (which is why the assignment operator is only called in the last example).