Why doesn't the copy constructor get called? - c++

I have this code for copying a polygon class. The problem I have is that in the end the vertices point to the original polygon class location. Since the copy constructor does not seem to be invoked. Why is that ?
Polygon::Polygon(const Polygon &aPolyToCopy)
{
int i;
vertices = new Vertex[aPolyToCopy.count];
for (i=0;i<aPolyToCopy.count;i++)
{
vertices[i].x = aPolyToCopy.vertices[i].x;
vertices[i].y = aPolyToCopy.vertices[i].y;
}
count = aPolyToCopy.count;
}
In a list template I do this
template <class T, int i>
bool SortedVector<T, i>::add ( const T& v )
{
myClass[myCurrent] = v; //Copy constructor not called ?
myCurrent++;
return true;
}
The template is
template <class T, int i>
class SortedVector
{
public:
int maxSize;
T myClass[i];
int myCurrent;
SortedVector();
~SortedVector();
bool add ( const T& v );
};

You're doing an assignment, you don't construct a new object here. If you define a custom copy constructor, you also need to overload operator=
See http://www.learncpp.com/cpp-tutorial/911-the-copy-constructor-and-overloading-the-assignment-operator/ for example.
If you would do something like x = Polygon(y), then your copy constructor would be called (followed by the default operator=). But don't use this workaround, just provide your operator=.

I think a problem in your Polygon class is that you have a vertices data member, which seems to be a raw pointer to a Vertex, used to store a raw array allocated with new[]:
vertices = new Vertex[aPolyToCopy.count];
You may need to overload also operator= (and the destructor), not only the copy constructor (see The Rule of Three); you haven't showed all the code of your Polygon class, so it's not clear if you defined proper copy assignment and destruction.
Note that you will simplify your code if you use a robust RAII container class like std::vector.
Just add a "std::vector<Vertex> vertices;" data member instead of a "Vertex* vertices" data member, and std::vector will take care of copy, cleanup, etc. You don't need to do anything: it's all automatically managed by std::vector.
#include <vector> // for std::vector
class Polygon
{
std::vector<Vertex> vertices;
public:
explicit Polygon(size_t vertexCount)
: vertices(vertexCount) // Build a polygon with specified vertices
{}
//
// Compiler generated copy constructor, operator= and destructor are fine.
//
};
In general, in C++ try to build classes assembling together convenient RAII building blocks like std::vector and other direct resource managers.

Related

How should I deal with the destructor, when making a custom vector with a template class?

I tried to make my custom Vector class, with a template class.
I expect I can put my Vector<int> into a Vector<Vector<int>> variable. At least that was what I was hoping for... but it keeps crashing at the destructor code.
Here's my code.
#include <iostream>
#include <string>
template <typename T>
class Vector {
T* data;
int capacity;
int length;
public:
typedef T value_type;
Vector() {}
Vector(int n) : data(new T[n]), capacity(n), length(0) {}
void push_back(T input) {
data[length++] = input;
}
T operator[](int i) { return data[i]; }
virtual ~Vector() { if (data) delete[] data; }
};
int main() {
Vector<Vector<int>> v(3);
Vector<int> vv(4);
v.push_back(vv);
}
So I thought, maybe I should use a copy constructor, since it seems the problem is that v is being deleted before vv. Well, if I just comment out the destructor code, it will work, but that doesn't seem right to me...
So I made a custom copy constructor like this:
Vector(const T& other) {
}
But it give me an error, saying "ambiguous overloading"... looking back, of course it is wrong, since T of data is different from T of other...
How can I make my custom Vector class work? (i.e. I want push_back work as I intended...)
The general issue
In class design, especially when memory/resource allocation is involved, you typically need to follow the "Rule of Five" (which used to be the "Rule of Three" before C++11):
If you implement any of:
A destructor
An copy/move assignment operator
A copy/move constructor
then you will probably need to implement all of them.
The reason is that each of them likely needs to have some resource management logic, beyond what the language gives you as a default.
The signatures of these five methods, for your class, would be:
Method
Signature
Copy constructor
Vector(const Vector&)
Move constructor
Vector(Vector&&)
Copy assignment operator
Vector& operator=(const Vector&)
Move assignment operator
Vector& operator=(Vector&&)
Destructor
~Vector() or virtual ~Vector()
Your specific class
In your specific case, there are several concrete problems:
As #UnholySheep suggests, you mis-declared the copy constructor.
You implemented a default constructor; but - it doesn't allocate anything, nor does it initialize anything! The data pointer holds arbitrary junk, and when you try to free it, bad things are likely to happen.
You are performing quite a lot of copying of T values, which for the outer vector would be Vector<int> values - and that can get expensive.
Even if you fixed the above, you should still implement the missing methods from the "rule of five".
Your default constructor leaves the object completely uninitialized.
Consider what happens when you declare a
Vector<int> foo;
foo essentially gets a random memory address as data, a random length and capacity. This will give fireworks if you free it.
Perhaps you sidestepped this issue by always creating your vector with a predefined size. Luckily, trying to create/destroy a Vector<Vector<int>> brings this to light, because the Vector<int>[] inside your container still contains these ticking timebombs.

Why c++ vector inner elements/array are copied when passed by value

Why does the inner elements of the vector are copied when the vector is passed by value?
#include<vector>
using namespace std;
// this func won't modify v[2].
// Meaning v[2] (and the whole inner array) was copied
// when v is passed to the func?
void modify(vector<int> v) {
v[2] = 100;
}
// this func modify v[2]
void modify(vector<int>& v) {
v[2] = 100;
}
int main() {
vector<int> v = {1,2,3,4,5,6};
// still same
modify(v);
// modified
modified2(v);
}
I find that it's strange that the actual content of the vector is copied when the vector is passed by value. I picture that the std::vector implementation must have a pointer field which maps to an address on heap, where the actual array is located. So when the vector is passed, even by value, the address should stay the same, pointing to the same content. Something like this:
#include<iostream>
using namespace std;
// a dummy wrapper of an array
// trying to mock vector<int>
class vector_int {
public:
int* inner_array; // the actual array
vector_int(int *a) {
inner_array = a;
}
int* at(int pos) {
return inner_array+pos;
}
};
// this passes the "mocked vector" by value
// but 'inner_array' is not copied
void modify(vector_int v) {
*(v.at(2)) = 10;
}
int main() {
int* a = new int[3] {1,2,3};
vector_int v = vector_int(a);
modify(v); // v[2] is modified
}
Is this assumption about the std::vector implementation correct? What makes the vector content being copied when passed by value?
EDIT
Thanks to alter igel's answer and UnholySheep's comment, I figured out the reason why std::vector has value sementics (or why the inner array got copied).
If the copy constructor class is defined explicitly in the class definition, the copy constructor will determine how the struct/class instance is copied when the variable is passed in a function call. So I can define a copy constructor to my vector_int, in which I copy the whole inner_array, like
#include<iostream>
using namespace std;
class vector_int {
public:
int* inner_array;
int len;
vector_int(int *a, int len) {
inner_array = a;
this->len = len;
}
int* at(int pos) {
return inner_array+pos;
}
// this is the copy constructor
vector_int(const vector_int &v2) {
inner_array = new int;
for (int i =0; i < v2.len; i++) {
*(inner_array+i) = *(v2.inner_array+i);
}
}
};
// Yay, the vector_int's inner_array is copied
// when this function is called
// and no modification of the original vector is done
void modify(vector_int v) {
*(v.at(2)) = 10;
}
int main() {
int* a = new int[3] {1,2,3};
vector_int v = vector_int(a,3);
//
modify(v);
}
I checked the source code of the stdlib implementation on my local computer (g++ Apple LLVM version 10.0.0). The std::vector defines a copy constructor which looks like this
template <class _Tp, class _Allocator>
vector<_Tp, _Allocator>::vector(const vector& __x)
: __base(__alloc_traits::select_on_container_copy_construction(__x.__alloc()))
{
size_type __n = __x.size();
if (__n > 0)
{
allocate(__n);
__construct_at_end(__x.__begin_, __x.__end_, __n);
}
}
which looks like it does an malloc for the actual copied array + copy the array.
C++ allows class types to provide their own code for what it means to be created, copied, moved, and destroyed, and that code is called implicitly, without any obvious function calls. This is called value semantics and it's what C++ uses where other languages resort to things like create_foo(foo), foo.clone(), destroy_foo(foo) or foo.dispose().
Each class can define the following special member functions:
Constructors, for putting the object into a valid initial state
A Destructor, for cleaning up responsibly
A Copy Constructor, for creating a new object that is a duplicate of another
A Move Constructor, for creating a new object by transferring the data of another
A Copy Assignment Operator, for duplicating an object into an existing object
A Move Assignment Operator, for transferring data between two existing objects
These are all functions that you can define to do whatever you want. But they are called implicitly, meaning that users of such a class don't see these function calls in their code, and they expect them to do predictable things. You should make sure that your classes behave predictably by following the Rule of Three/Five/Zero.
There are of course other tools for sharing data, like pass-by-reference, which you already know about.
Lots of classes in the standard library use these special member functions to implement special behaviors that are very useful and help users write safe, correct code. For example:
std::vector when copied, will always have identical elements, though the underlying array and objects contained will be separate.
std::unique_ptr wraps a resource that has only one owner. To enforce this, it can't be copied.
std::shared_ptr wraps a resource that has many owners. It's not totally clear when to clean up such a resource, so copying a shared_ptr performs automatic reference counting, and the resource is cleaned up only when the last owner is done with it.
This is because vector has value semantics: when you copy it you get a true copy of all the elements.

Optimal creation new empty element in std::map

For inserting new elements std::map requires presence std::pair object.
I didn't find an alternative method to add a new element into std::map without constructing such std::pair object.
But suppose the std::map value is a heavy object consuming a lot of resources. Inserting such element into std::map constraints one unnecessary copy. In the case
I have some object X needed to be copied directly into std::map, std authors constrain me to perform this copy in two steps:
copy X->std::pair
copy pair obj -> std::map insert location.
How to eliminate these unneeded copy? Implementing Move constructor doesn't solve my problem - the copy still exists.
I suspect some method in std::map which inserts a new empty element with some key but no value, without calling any constructor for the value. Then I can move the value to thereby my own way.
But I don't find such method in std::map!
the std::map value is a heavy object consuming a lot of resources. Inserting such element into std::map constraints one unnecessary
copy. How to eliminate these unneeded copy?
You are right about this and std::map::emplace is the only solution what we have available now. A small explanation about the use of std::map::emplace from cppreference.com is given below:
Careful use of emplace allows the new element to be constructed while
avoiding unnecessary copy or move operations. The constructor of the
new element (i.e. std::pair<const Key, T>) is called with exactly the
same arguments as supplied to emplace, forwarded via
std::forward<Args>(args)....
That means the a class-instances can be constructed in-place at the time of map insert(i.e, instead of constructing and copying), via std::map::emplace, when you provide a contractor in the class with exactly same arguments. And then, you need to use std::map::emplace along with std::piecewise_construct and std::forward_as_tuple(assuming that the class contains more than one member).
myMap.emplace(
std::piecewise_construct,
std::forward_as_tuple(/*key of map*/),
std::forward_as_tuple(/*all the members which you want to constrct in place*/)
);
To demonstrate the above case, I have made a small sample code in which the members of ClassA will be constructed in place without calling any of the special member functions. To make it sure, I have disabled default, copy and move constructors.
SEE LIVE HERE
#include <iostream>
#include <map>
#include <tuple>
class ClassA
{
int _val;
std::string _str;
public:
explicit ClassA(const int val, const std::string& str) : _val(val), _str(str)
{
std::cout << "A class: C'tor called...!\n";
}
// disable the following
ClassA() = delete;
ClassA(const ClassA&) = delete;
ClassA& operator=(const ClassA&) = delete;
ClassA(ClassA&&) = delete;
ClassA& operator=(ClassA&&) = delete;
};
class ClassB
{
ClassA _aObj;
public:
explicit ClassB(const int val, const std::string& str) : _aObj(val, str)
{
std::cout << "B class: C'tor called...!\n";
}
// disable the following
ClassB() = delete;
ClassB(const ClassB&) = delete;
ClassB& operator=(const ClassB&) = delete;
ClassB(ClassB&&) = delete;
ClassB& operator=(ClassB&&) = delete;
};
int main()
{
std::map<int, ClassB> myMap;
myMap.emplace(
std::piecewise_construct,
std::forward_as_tuple(1),
std::forward_as_tuple(1, "some string")
);
return 0;
}
Output:
A class: C'tor called...!
B class: C'tor called...!
Update: On the other hand,
The element may be constructed even if
there already is an element with the key in the container, in which
case the newly constructed element will be destroyed immediately.
That means, your expectation(or assumption) of:
" I suspect some method in std::map which inserts a new empty element with some key but no value, without calling any constructor for the value. Then I can move the value to thereby my own way. "
is not possible to achieve, by above mentioned std::map::emplace way. As #aschepler pointed out in the comments, you can have maps with sometimes(optional) keys and no values by using the C++17 feature std::optional.
For that, you need to make the values as optional as follows and of course the compiler version support C++17 or later.
std::map<Key, std::optional<Value>> myMap;
Now you can construct an object anytime in the code and after a while, you can move it to appropriate key-value(i.e, entry). Last but not least, don't forget to provide default move-c'ntors
SEE SAMPLE CODE HERE
#include <optional>
class ClassA {
/* same as before*/
public:
// disable the copy c'tor
// enable move c'ntors
ClassA(ClassA&&) = default;
ClassA& operator=(ClassA&&) = default;
};
class ClassB {
/* same as before*/
public:
// disable the copy c'tor
// enable move c'ntors
ClassB(ClassB&&) = default;
ClassB& operator=(ClassB&&) = default;
};
int main() {
std::map<int, std::optional<ClassB>> myMap;
// created without calling any constructors
myMap.emplace(1, std::nullopt);
//later in the code
ClassB bObj{1, "JeJo"};
// again after..... move it to the required key-value
myMap[1] = std::move(bObj);
return 0;
}
Output:
A class: C'tor called...!
B class: C'tor called...!
You are looking for std::map::emplace
https://en.cppreference.com/w/cpp/container/map/emplace

Copy Constructor with assignment overloading syntax?

I am working with writing the big five(copy constructor, copy assignment operator, move constructor, move assignment operator, destructor). And I've hit a bit of a snag with the copy constructor syntax.
Say I have a class foo that has the following private members:
template<class data> // edit
class foo{
private:
int size, cursor; // Size is my array size, and cursor is the index I am currently pointing at
data * dataArray; // edit
}
If I were to write a constructor for this of some arbitrary size X it would look like this.
template<class data> // edit
foo<data>::foo(int X){
size = X;
dataArray = new data[size];
cursor = 0; // points to the first value
}
Now if I wanted to make a copy constructor of another object called bar I'd need to make the following:
template<class data> // edit
foo<data>::foo(foo &bar){
foo = bar; // is this correct?
}
Assuming I have the overloaded = from the code below:
template<class data> // edit
foo<data>::operator=(foo &someObject){
if(this != someObject){
size = someObject.size;
cursor = someObject.cursor;
delete[] dataArray;
dataArray = new data[size];
for(cursor = 0; cursor<size-1;cursor++)
dataArray[cursor] = someObject.dataArray[cursor];
}
else
// does nothing because it is assigned to itself
return *this;
}
Is my copy constructor correct? Or should foo = bar instead be *this = bar ?
I'm still new to templated constructors so if I made any errors in the code please let me know I will correct it.
EDIT 1: Thanks to the answer provided below by Marcin I have made some edits to the code above to make it more syntatically correct and commented them with //edit they are summarized in the list below:
previously template<classname data>, which is incorrect must be template <typename data> or template <class data> for functions and classes respectively.
previously int*dataArray; this missuses the template and should be data* dataArray;
The best way to achieve what you want is to use a class that already handles assignment, copying and moving, taking care of its memory management for you. std::vector does exactly this, and can directly replace your dynamically allocated array and size. Classes that do this are often referred to as RAII classes.
Having said that, and assuming this is an exercise in correctly implementing the various special member functions, I'd suggest that you proceed via the copy and swap idiom. (See What is the copy and swap idiom? on SO, for more details and commentary). The idea is to define the assignment operation in terms of the copy constructor.
Start with the members, constructor and destructor. These define the ownership semantics of the members of your class:
template <class data>
class foo {
public:
foo(const size_t n);
~foo();
private:
size_t size; // array size
size_t cursor; // current index
data* dataArray; // dynamically allocated array
};
template <class data>
foo<data>::foo(const size_t n)
: size(n), cursor(0), dataArray(new data[n])
{}
template <class data>
foo<data>::~foo() {
delete[] dataArray;
}
Here, memory is allocated in the constructor and deallocated in the destructor.
Next, write the copy constructor.
template <class data>
foo<data>::foo(const foo<data>& other)
: size(other.size), cursor(other.cursor), dataArray(new data[other.size]) {
std::copy(other.dataArray, other.dataArray + size, dataArray);
}
(along with the declaration, foo(const foo& other); inside the class body).
Notice how this uses member initialiser lists to set the member variables to the values in the other object. A new allocation is performed, and then in the body of the copy constructor you copy the data from the other object into this object.
Next comes the assignment operator. Your existing implementation has to perform a lot of manipulation of pointers, and isn't exception safe. Let's look at how this could be done more simply and more safely:
template <class data>
foo<data>& foo<data>::operator=(const foo<data>& rhs) {
foo tmp(rhs); // Invoke copy constructor to create temporary foo
// Swap our contents with the contents of the temporary foo:
using std::swap;
swap(size, tmp.size);
swap(cursor, tmp.cursor);
swap(dataArray, tmp.dataArray);
return *this;
}
(along with the declaration in-class, foo& operator=(const foo& rhs);).
[-- Aside: You can avoid writing the first line (explicitly copying the object) by accepting the function argument by value. It's the same thing, and might be more efficient in some cases:
template <class data>
foo<data>& foo<data>::operator=(foo<data> rhs) // Note pass by value!
{
// Swap our contents with the contents of the temporary foo:
using std::swap;
swap(size, rhs.size);
swap(cursor, rhs.cursor);
swap(dataArray, rhs.dataArray);
return *this;
}
However, doing so may cause ambiguous overloads if you also define a move assignment operator. --]
The first thing this does is create a copy of the object being assigned from. This makes use of the copy constructor, so the details of how an object is copied need only be implemented once, in the copy constructor.
Once the copy has been made, we swap our internals with the internals of the copy. At the end of the function body, the tmp copy goes out of scope, and its destructor cleans up the memory. But this isn't the memory that was allocated at the beginning of the function; it's the memory our object used to hold, before we swapped our state with the temporary.
In this way, the details of allocating, copying and deallocating are kept where they belong, in the constructors and the destructor. The assignment operator simply copies and swaps.
This has a further advantage, over and above being simpler: It's exception safe. In the code above, an allocation error could cause an exception to be thrown while creating the temporary. But we haven't modified the state of our class yet, so our state remains consistent (and correct) even when the assignment fails.
Following the same logic, the move operations become trivial. The move constructor must be defined to simply take ownership of the resource and leave the source (the moved-from object) in a well-defined state. That means setting the source's dataArray member to nullptr so that a subsequent delete[] in its destructor doesn't cause problems.
The move assignment operator can be implemented similarly to the copy assignment, although in this case there's less concern with exception safety since you're just stealing the already-allocated memory of the source object. In the complete example code, I opted to simply swap the state.
A complete, compilable-and-runnable example can be seen here.
Your foo class does not internally use data template parameter. I suppose you wanted to use it here:
int * dataArray; // should be: data * dataArray;
You also are not allowed to use classname keyword but typename or class. You have also lots of other compile errors in your code.
Your copy constructor is wrong, it will not compile:
foo = bar; // is this correct? - answer is NO
foo is a class name in this context, so your assumption is correct. *this = someObject this would work (with additional fixes, at least dataArray must be set to nullptr), but your class variables would be default constructed first by copy constructor only to be overwritten by assignment operator, so its quiet non efficent. For more read here:
Calling assignment operator in copy constructor
Is it bad form to call the default assignment operator from the copy constructor?

How do I avoid invoking the copy constructor with insertion iterators

template<typename OutputIterator>
void BlitSurface::ExtractFrames(OutputIterator it,
int frame_width, int frame_height,
int frames_per_row, int frames_per_column,
bool padding) const
{
SDL_Surface ** temp_surf = SDL_Ex_ExtractFrames(_surface, frame_width, frame_height, frames_per_row, frames_per_column, padding);
int surface_count = frames_per_row * frames_per_column;
for(int i=0; i<surface_count; ++i)
{
BlitSurface bs;
bs._surface = temp_surf[i];
*it = bs;
++it;
}
delete [] temp_surf;
}
I have this function, which works fine. Only problem is that I don't want to invoke the copy constructor, because it copies the entire surface, and I only need to copy the pointer. I just want to use the default constructor, then set the member _surface to temp_surface[i], like this:
for(int i=0; i<surface_count; ++i)
{
it->_surface = temp_surf[i];
++it;
}
That works for normal iterators, but not for insertion iterators. How can I fix it to work for both?
Really what you want is a move InputIterator for use with the insertion OutputIterator. Since that doesn't exist in C++03, there needs to be an alternative way to signal that a "shallow" move, not a "deep" copy, is desired.
A simple state flag in the object itself won't work, because the implementation is allowed to copy the object around randomly before actually putting it in the container. (For optimization's sake, you know it won't, but it's nice not to worry about debug builds.)
Off the top of my head, it sounds like a job for a custom allocator. The default allocator copy-constructs using placement new; you can define an alternate constructor and call it using placement new instead.
template< typename T >
struct move_traits {
typedef T must_copy_type; // does not exist in specializations
};
template< typename T >
struct move_if_possible_allocator
: std::allocator< T > {
typedef move_traits<T> traits;
// SFINAE selects this function if there is a specialization
void construct( typename traits::may_move_type *obj, T &value ) {
new( obj ) T(); // default construct
traits::move_obj( *obj, value ); // custom routine
}
// SFINAE selects this function if traits is the base template
void construct( typename traits::must_copy_type *obj, T const &value ) {
new( obj ) T( value ); // copy construct (fallback case)
}
// define rebind... exercise for the reader ;v)
};
template<>
struct move_traits< BlitSurface > {
typedef T may_move_type; // signal existence of specialization
static void move_obj( BlitSurface &out, BlitSurface &in ) {
// fill out and clear in
}
}
Of course, it's perfectly fine to add state to BlitSurface to disable moving by move_obj, if some objects are in fact copied into the container.
It's mentioned that a copy constructor is being called. In the example that provided it seems like the container is probably defined to hold BlitSurface. Something like std::vector< BlitSurface>. This is a guess on my part from the following lines:
BlitSurface bs;
bs._surface = temp_surf[i];
*it = bs;
My understanding is that all std containers will make a copy upon insert. From there on you can use the objects in the container by reference. If you do not want the copy constructor to be called on BlitSurface then I would suggest that the container store a pointer to BlitSurface. This way when the container does its copy on insert the object it actually makes a copy of is a pointer (not the BlitSurface object that is pointed to).
BlitSurface* bs = new BlitSurface;
bs->_surface = temp_surf[i];
*it = bs;
Keep in mind that that this approach allocates on heap (i.e. new) so memory will have to be explicitly deleted later or some type of smart pointer can be used in the container to take care of the deletion (std::vector< boost::shared_ptr< BlitSurface> > ).