Prevent object copy on return - c++

I have this:
struct Point
{
size_t x;
size_t y;
~Point()
{
std::cout << "Destro" << "\n";
}
};
const Point& getPoint()
{
return { 100, 120 };
}
int main()
{
Point p = getPoint();
std::cout << "Exit" << "\n";
}
and the result is
Destro
Exit
Destro
I'm basically trying to make the getPoint method not have to copy the Point class.
Here is what's happening so far:
Point Created
Point copied to the result
Point destroyed
How can I make it so that Point is only destroyed once?

You need to return by value instead of reference. Using
Point getPoint()
{
return { 100, 120 };
}
Allows C++17's guaranteed copy elision to kick in which causes Point p = getPoint(); to act as if it was Point p{ 100, 120 };
Side note: Never, Never, Never, return a function local object by reference. That object will be destroyed at the end of the function leaving you with a dangling reference and using that is undefined behavior.

Here's an example of what it looks like you're trying to achieve...
#include <iostream>
struct Point {
size_t x;
size_t y;
~Point() { std::cout << "Destructor called\n"; }
// Explicitly deleting the Copy Constructor only to illustrate a point.
Point(const Point& other) = delete;
};
const Point makePoint(size_t a, size_t b) {
return Point{ a, b };
}
int main() {
Point a = makePoint(3, 5);
std::cout << a.x << ',' << a.y << '\n';
}
Output:
3,5
Destructor called
If you noticed, I explicitly deleted the Copy Constructor and left the Assignment Operator undeclared so that it will use the default. The struct is still using the default constructor and I didn't define a User Defined constructor.
In makePoint() I added two parameters/arguments to the function so that the user can set any values to the Point object. The function is returning a const Type object. The return statement in the function is using:
return Point{a, b};
instead of
return Point(a, b);
The latter will fail to compile because there is no user-defined constructor. However, the former works because I'm using brace-initialization. This will allow construction of the object on return instead of creating a temporary on the stack frame of the function and copying that temporary as its return value. This is a form of Copy Elision.
Now, if you want to be able to copy this object, you can remove the deleted constructor and allow the class to use its default copy constructor. The semantics of the Copy Elision will still work.
This will have the same exact results. I showed the explicit deletion of the Copy Constructor to initially prevent any Copying semantics. Then explained how the code works so you can take the original above and remove the line for the deleted copy constructor and it will still work the same:
struct Point {
size_t x;
size_t y;
~Point() { std::cout << "Destructor called\n"; }
};
const Point makePoint(size_t a, size_t b) {
return Point{ a, b };
}
The functionality or behind the scenes magic is happening within the function makePoint() and that it returns a const object and uses brace-initialization of the class.

Related

Why don't reference members refer the assigned variable on nested vectors? What's a proper way to declare an alternative way to access a class member?

I would like to declare an alternative way to access a class member (an array position specifically), as in
class Foo {
int a[2];
int &a_first = a[0];
};
such that any access to a_first in a Foo instance is for all purposes equivalent to accessing a[0] of that same instance.
The code above works as I expected with singular instances and single vectors of the class, but when used on a nested vector the reference address differs from the member address:
#include <iostream>
#include <vector>
class A {
public:
int m;
int &mref = m;
};
int main()
{
A a;
std::cout << (&a.m == &a.mref) << '\n'; // output: 1
std::vector<A> av1(1);
std::cout << (&av1[0].m == &av1[0].mref) << '\n'; // output: 1
std::vector<std::vector<A>> av2(1, std::vector<A>(1));
std::cout << (&av2[0][0].m == &av2[0][0].mref) << '\n'; // output: 0
return 0;
}
I thought reference variables acted as aliases of their assigned variable and were resolved at compile time without being assigned any actual memory at runtime, unlike pointers. Why is this not consistent with the behavior displayed above? What would be a correct way to achieve the alias I want?
The code above works as I expected
Actually it doesn't:
class A {
public:
int m{};
int &mref = m;
};
int main()
{
A a;
A a2 = a;
std::cout << (&a2.m == &a2.mref) << '\n'; // output: 0
};
A reference can be bound only on initialization. Copying will copy the value, not re-bind the reference. So any copy of an object of type A will mess up your reference. This is what happens in your nested vector example. You don't need a nested vector to see this. Try and push in a vector<A>, the vector will have to resize and during the resize will copy its elements, messing your reference.
I thought reference variables acted as aliases of their assigned variable ...
True
... and were resolved at compile time without being assigned any actual memory at runtime, unlike pointers.
Not always. You cannot always resolve at compile time the reference, in which case the reference will actually be implemented with a pointer behind the scenes.
Possible solutions:
use std::reference_wrapper, the copy assignment operator rebinds the reference, but you will need to implement custom copy constructor/assignments for your class:
class A {
public:
int m{};
std::reference_wrapper<int> mref = m;
A() = default;
A(const A& other) noexcept
: m{other.m},
mref{m}
{}
A& operator=(const A& other) noexcept
{
m = other.m;
mref = m;
return *this;
}
};
use a method that returns a reference to the variable
class A {
public:
int m{};
int& mref() { return m; }
const int& mref() const { return m; }
};

Copy constructor is called instead of move constructor - why?

I have this code, taken from here by the way http://www.cplusplus.com/doc/tutorial/classes2/
// move constructor/assignment
#include <iostream>
#include <string>
#include <utility>
using namespace std;
class Example6
{
string* ptr;
public:
Example6(const string& str) :
ptr(new string(str))
{
cout << "DONT MOVE " << '\n';
}
~Example6()
{
delete ptr;
}
// move constructor
Example6(Example6&& x) :
ptr(x.ptr)
{
cout << "MOVE " << '\n';
x.ptr = nullptr;
}
// move assignment
Example6& operator=(Example6&& x)
{
delete ptr;
ptr = x.ptr;
x.ptr = nullptr;
return *this;
}
// access content:
const string& content() const
{
return *ptr;
}
// addition:
Example6 operator+(const Example6& rhs)
{
return Example6(content() + rhs.content());
}
};
int main()
{
Example6 foo("Exam");
Example6 bar = Example6("ple"); // move-construction
foo = foo + bar; // move-assignment
cout << "foo's content: " << foo.content() << '\n';
return 0;
}
I only added output in constructor to see which is being called. To my surprise it is always the first one, copy constructor. Why does it happen? I did some research and found some info about elision. Is it somehow possible to prevent it and always call move constructor?
Also, as a side note, as I said this code is from cplusplus.com. However, I read about move semantics in some other places and I wonder if this move constructor here is done right. Shouldn't it call
ptr(move(x.ptr))
instead of just
ptr(x.ptr)
The way I understand this, if we use the second option, then we are calling copy constructor of string, instead of move, because x is rvalue reference that has a name, so it is really lvalue and we need to use move to cast it to be rvalue. Do i miss something, or is it really tutorial's mistake?
Btw, adding move doesn't solve my first problem.
So anything with a name is an lvalue.
An rvalue reference with a name is an lvalue.
An rvalue reference will bind to rvalues, but it itself is an lvalue.
So x in ptr(x.ptr) is an rvalue reference, but it has a name, so it is an lvalue.
To treat it as an rvalue, you need to do ptr( std::move(x).ptr ).
Of course, this is mostly useless, as moving a ptr does nothing as ptr is a dumb raw pointer.
You should be following the rule of 0 here.
class Example6 {
std::unique_ptr<string> ptr;
public:
Example6 (string str) : ptr(std::make_unique<string>(std::move(str))) {cout << "DONT MOVE " << '\n';}
Example6():Example6("") {}
~Example6 () = default;
// move constructor
Example6 (Example6&& x) = default;
// move assignment
Example6& operator= (Example6&& x) = default;
// access content:
const string& content() const {
if (!ptr) *this=Example6{};
return *ptr;
}
// addition:
Example6 operator+(const Example6& rhs) {
return Example6(content()+rhs.content());
}
};
because business logic and lifetime management don't belong intermixed in the same class.
While we are at it:
// addition:
Example6& operator+=(const Example6& rhs) & {
if (!ptr) *this = Example6{};
*ptr += rhs.content();
return *this;
}
// addition:
friend Example6 operator+(Example6 lhs, const Example6& rhs) {
lhs += rhs;
return lhs;
}
Copy constructor is called ... - why?
The premise of your question is faulty: The copy constructor is not called. In fact, the class is not copyable.
The first constructor is a converting constructor from std::string. The converting constructor is called because Example6 objects are initialised with a string argument. Once in each of these expressions:
Example6 foo("Exam")
Example6("ple")
Example6(content() + rhs.content()
... instead of move constructor
There are a few copy-initialisations by move in the program. However, all of them can be elided by the compiler.
Is it somehow possible to prevent it and always call move constructor?
There are a few mistakes that can prevent copy elision. For example, if you wrote the addition operator like this:
return std::move(Example6(content()+rhs.content()));
The compiler would fail to elide the move and probably tell you about it if you're lucky:
warning: moving a temporary object prevents copy elision
Shouldn't it call
ptr(move(x.ptr))
instead of just
ptr(x.ptr)
There's no need. Moving a pointer is exactly the same as copying a pointer. Same holds for all fundamental types.
The way I understand this, if we use the second option, then we are calling copy constructor of string, instead of move
ptr is not a string. It is a pointer to a string. Copying a pointer does nothing to the pointed object.
PS. The example program is quite bad quality. There should never be owning bare pointers in C++.
I can say your class does not have a copy constructor.
Because copy ctor parameter have to be const and reference
class Example6{
public:
Example6(const Example6 &r);
};

making public member read only

class A{
private:
int a;
public:
const int &ref = a;
};
int main() {
A obj;
obj.a = 20; // error cause private
obj.ref = 30; // not private but const so ERROR
return 0;
}
I'm trying to make a member variable accessible but read only through the interface. Currently I've tried this approach and it seems to compile fine. I made a const reference to my original variable int a and made it public. Is there anything that's wrong with this practice that I might be missing out? Or is this example safe and sound to use for practical purposes?
Nothing wrong with providing a member function with const correctness applied (and I've used that too and intend to do so always), but I'm asking is there any thing wrong with this way if I have to provide a variable that is only read-only.
Thankyou :)
class A{
private:
int a;
public:
const int &ref = a;
};
is there any thing wrong with this way if I have to provide a variable that is only read-only
There are at least a couple drawbacks with this design decision for class A.
1: Class Size
Also as Dieter Lücking mentions in a
comment:
increasing the size of the class, needlessly
2: Copy Semantics
It breaks the compiler generated copy assignment operator. For example, the following code behavior is generally desirable but doesn't work.
A obj1;
// ...
A obj2;
// make changes to 'obj2'
// Update 'obj1' with the changes from 'obj2'
obj1 = obj2; // This copy doesn't work!
More information:
Should I prefer pointers or references in member data?
Assignment operator with reference class member
Thinking in C++, 2nd ed. Volume 1 ©2000 by Bruce Eckel, 11: References & the Copy-Constructor
There are certain rules when using references:
A reference must be initialized when it is created. (Pointers can be initialized at any time.)
Once a reference is initialized to an object, it cannot be changed to refer to another object. (Pointers can be pointed to another object at any time.)
You cannot have NULL references. You must always be able to assume that a reference is connected to a legitimate piece of storage.
It may be possible to implement a custom assignment operator but that's more code to maintain (i.e., another drawback in my opinion).
#include <iostream>
class A
{
private:
int a;
public:
explicit A(int value) : a(value) {}
A& operator=(const A& other)
{
a = other.a;
return *this;
}
const int& ref = a;
};
int main()
{
A obj1(10);
std::cout << "1: " << obj1.ref << "\n";
A obj2(20);
std::cout << "2: " << obj2.ref << "\n";
obj1 = obj2;
std::cout << "1: " << obj1.ref << "\n";
return 0;
}
The idiomatic way to address this issue is to use a proper accessor function.
class A {
private:
int a;
public:
int getA() const { return a; }
};
The standard way to do this in C++ is by making the actual member private but including a public 'getter' method for the interface, as below:
class A{
private:
int a;
public:
int get_a() const { return a; }
A() : a(20) {}
};
int main() {
A obj;
int n = obj.get_a(); // n = 20
return 0;
}
The user cannot set the value of A::a but can use A::get_a to retrieve its value.

segmentation fault in overloading operator =

I just got a seg fault in overloading the assignment operator for a class FeatureRandomCounts, which has _rects as its pointer member pointing to an array of FeatureCount and size rhs._dim, and whose other date members are non-pointers:
FeatureRandomCounts & FeatureRandomCounts::operator=(const FeatureRandomCounts &rhs)
{
if (_rects) delete [] _rects;
*this = rhs; // segment fault
_rects = new FeatureCount [rhs._dim];
for (int i = 0; i < rhs._dim; i++)
{
_rects[i]=rhs._rects[i];
}
return *this;
}
Does someone have some clue? Thanks and regards!
*this = rhs;
calls operator=(), which is the function you are writing. Cue infinite recursion, stack overflow, crash.
Also, if you used a std::vector rather than a C-style array, you probably would not need to implement operator=() at all.
As mentioned, you have infinite recursion; however, to add to that, here's a foolproof way to implement op=:
struct T {
T(T const& other);
T& operator=(T copy) {
swap(*this, copy);
return *this;
}
friend void swap(T& a, T& b);
};
Write a correct copy ctor and swap, and exception safety and all edge cases are handled for you!
The copy parameter is passed by value and then changed. Any resources which the current instance must destroy are handled when copy is destroyed. This follows current recommendations and handles self-assignment cleanly.
#include <algorithm>
#include <iostream>
struct ConcreteExample {
int* p;
std::string s;
ConcreteExample(int n, char const* s) : p(new int(n)), s(s) {}
ConcreteExample(ConcreteExample const& other)
: p(new int(*other.p)), s(other.s) {}
~ConcreteExample() { delete p; }
ConcreteExample& operator=(ConcreteExample copy) {
swap(*this, copy);
return *this;
}
friend void swap(ConcreteExample& a, ConcreteExample& b) {
using std::swap;
//using boost::swap; // if available
swap(a.p, b.p); // uses ADL (when p has a different type), the whole reason
swap(a.s, b.s); // this 'method' is not really a member (so it can be used
// the same way)
}
};
int main() {
ConcreteExample a (3, "a"), b (5, "b");
std::cout << a.s << *a.p << ' ' << b.s << *b.p << '\n';
a = b;
std::cout << a.s << *a.p << ' ' << b.s << *b.p << '\n';
return 0;
}
Notice it works with either manually managed members (p) or RAII/SBRM-style members (s).
*this = rhs; // segment fault
This is definitively not the way to do it. You call = recursively, not calling the built in assignment operator. Assign variables one by one. Don't be lazy.
The following line:
*this = rhs; // segment fault
will recursively call your operator=() function resulting in a stack overflow.
You should probably replace it with straight-forward assignments of the various member fields.
As Neil said, using something like std::vector<> will remove much of the responsibility away from your code. If for whatever reason you can't or don't want to use std::vector<>, you might also want to consider using the 'swap idiom' for your assignment operator. This will make the function exception safe (if the allocation of the memory for FeatureCount array fails and throws an exception, the original object that's being assigned to will be left unchanged). Something like the following:
void FeatureRandomCounts::swap( FeatureRandomCounts& other)
{
FeatureCount* tmp_rects = other._rects;
int tmp_dim = other._dim; // or whatever type _dim is
// similarly for other members of FeatureRandomCounts...
// now copy the other contents to
this->_rects = other._rects;
this->_dim = other._dim;
// assign other members of rhs to lhs
other._rects = tmp_rects;
other._dim = tmp_dim;
// etc.
return;
}
Now your assignment can look like:
FeatureRandomCounts & FeatureRandomCounts::operator=(const FeatureRandomCounts &rhs)
{
FeatureRandomCounts tmp( rhs); // make a copy
tmp.swap( *this); // swap the contents of the copy and *this
return *this;
// the contents of tmp (which has the old
// stuff that was in *this) gets destructed
}
Note that you need a proper copy constructor for this to work, but given the Big 3 rule you already need a proper copy ctor.

Is this C++ reassignment valid?

Sorry for the basic question, but I'm having trouble finding the right thing to google.
#include <iostream>
#include <string>
using namespace std;
class C {
public:
C(int n) {
x = new int(n);
}
~C( ) {
delete x;
}
int getX() {return *x;}
private:
int* x;
};
void main( ) {
C obj1 = C(3);
obj1 = C(4);
cout << obj1.getX() << endl;
}
It looks like it does the assignment correctly, then calls the destructor on obj1 leaving x with a garbage value rather than a value of 4. If this is valid, why does it do this?
If there is a class C that has a constructor that takes an int, is this code valid?
C obj1(3);
obj1=C(4);
Assuming C has an operator=(C) (which it will by default), the code is valid. What will happen is that in the first line obj1 is constructed with 3 as a the parameter to the constructor. Then on the second line, a temporary C object is constructed with 4 as a parameter and then operator= is invoked on obj1 with that temporary object as a parameter. After that the temporary object will be destructed.
If obj1 is in an invalid state after the assignment (but not before), there likely is a problem with C's operator=.
Update: If x really needs to be a pointer you have three options:
Let the user instead of the destructor decide when the value of x should be deleted by defining a destruction method that the user needs to call explicitly. This will cause memory leaks if the user forgets to do so.
Define operator= so that it will create a copy of the integer instead of a copy of the value. If in your real code you use a pointer to something that's much bigger than an int, this might be too expensive.
Use reference counting to keep track how many instances of C hold a pointer to the same object and delete the object when its count reaches 0.
If C contains a pointer to something, you pretty much always need to implement operator=. In your case it would have this signature
class C
{
public:
void operator=(const C& rhs)
{
// For each member in rhs, copy it to ourselves
}
// Your other member variables and methods go here...
};
I do not know enough deep, subtle C++ to explain the problem you are encountering. I do know, however, that it's a lot easier to make sure a class behaves the way you expect if you follow the Rule of Three, which the code you posted violates. Basically, it states that if you define any of the following you should define all three:
Destructor
Copy constructor
Assignment operator
Note as well that the assignment operator implementation needs to correctly handle the case where an object is assigned to itself (so-called "self assignment"). The following should work correctly (untested):
#include <iostream>
#include <string>
using namespace std;
class C {
public:
C(int n) {
x = new int(n);
}
C(const C &other): C(other.getX()) { }
~C( ) {
delete x;
}
void operator=(const C &other) {
// Just assign over x. You could reallocate if you first test
// that x != other.x (the pointers, not contents). The test is
// needed to make sure the code is self-assignment-safe.
*x = *(other.x);
}
int getX() {return *x;}
private:
int* x;
};
void main( ) {
C obj1 = C(3);
obj1 = C(4);
cout << obj1.getX() << endl;
}
Basically you are trying to re-implement a smart pointer.
This is not trivial to get correct for all situations.
Please look at the available smart pointers in the standard first.
A basic implementation (Which will fail under certain situations (copy one of the standard ones to get a better one)). But this should cover the basics:
class X
{
int* data;
public:
// Destructor obvious
~X()
{
delete data;
}
// Easy constructor.
X(int x)
:data(new int(x))
{}
// Copy constructor.
// Relatively obvious just do the same as the normal construcor.
// Get the value from the rhs (copy). Note A class is a friend of
// itself and thus you can access the private members of copy without
// having to use any accessor functions like getX()
X(X const& copy)
:data(new int(copy.x))
{}
// Assignment operator
// This is an example of the copy and swap idiom. This is probably overkill
// for this trivial example but provided here to show how it is used.
X& operator=(X const& copy)
{
X tmp(copy);
this->swap(tmp);
return this;
}
// Write a swap() operator.
// Mark it is as no-throw.
void swap(X& rhs) throws()
{
std::swap(data,rhs.data);
}
};
NEW:
What's happening is that your destructor has deallocated the memory allocated by the constructor of C(4). So the pointer you have copied over from C(4) is a dangling pointer i.e. it still points to the memory location of the deallocated memory
class C {
public:
C(int n) {
x = new int(n);
}
~C( ) {
//delete x; //Don't deallocate
}
void DeallocateX()
{
delete x;
}
int getX() {return *x;}
private:
int* x;
};
int main(int argc, char* argv[])
{
// Init with C(3)
C obj1 = C(3);
// Deallocate C(3)
obj1.DeallocateX();
// Allocate memory and store 4 with C(4) and pass the pointer over to obj1
obj1 = C(4);
// Use the value
cout << obj1.getX() << endl;
// Cleanup
obj1.DeallocateX();
return 0;
}
Be explicit about ownership of pointers! auto_ptr is great for this. Also, when creating a local don't do C obj1 = C(3) that creates two instances of C and initializes the first with the copy constructor of the second.
Heed The Guru.
class C {
public:
C(int n) : x(new int(n)) { }
int getX(){ return *x; }
C(const C& other) : x(new int(*other.x)){}
C& operator=(const C& other) { *x = *other.x; return *this; }
private:
std::auto_ptr<int> x;
};
int main() {
C obj1(3);
obj1 = C(4);
std::cout << obj1.getX() << std::endl;
}
When are you testing the value of obj1? Is it after you leave the scope?
In your example, obj1 is a stack object. That means as soon as you leave the function in which it defined, it gets cleaned up (the destructor is called). Try allocating the object on the heap:
C *obj1 = new C(3);
delete obj1;
obj1 = new C(4);