How to dynamically allocate arrays in C++ - c++

I know how to dynamically allocate space for an array in C. It can be done as follows:
L = (int*)malloc(mid*sizeof(int));
and the memory can be released by:
free(L);
How do I achieve the equivalent in C++?
Specifically, how do I use the new and delete[] keywords? Especially in the context of creating/destroying a linked list node, or creating and destroying an array whose size is given by a variable during compile time?

int* L = new int[mid];
delete[] L;
for arrays (which is what you want) or
int* L = new int;
delete L;
for single elements.
But it's more simple to use vector, or use smartpointers, then you don't have to worry about memory management.
std::vector<int> L(mid);
L.data() gives you access to the int[] array buffer and you can L.resize() the vector later.
auto L = std::make_unique<int[]>(mid);
L.get() gives you a pointer to the int[] array.

Following Info will be useful :
Source : https://www.learncpp.com/cpp-tutorial/6-9a-dynamically-allocating-arrays/
Initializing dynamically allocated arrays
If you want to initialize a dynamically allocated array to 0, the syntax is quite simple:
int *array = new int[length]();
Prior to C++11, there was no easy way to initialize a dynamic array to a non-zero value (initializer lists only worked for fixed arrays). This means you had to loop through the array and assign element values explicitly.
int *array = new int[5];
array[0] = 9;
array[1] = 7;
array[2] = 5;
array[3] = 3;
array[4] = 1;
Super annoying!
However, starting with C++11, it’s now possible to initialize dynamic arrays using initializer lists!
int fixedArray[5] = { 9, 7, 5, 3, 1 }; // initialize a fixed array in C++03
int *array = new int[5] { 9, 7, 5, 3, 1 }; // initialize a dynamic array in C++11
Note that this syntax has no operator= between the array length and the initializer list.
For consistency, in C++11, fixed arrays can also be initialized using uniform initialization:
int fixedArray[5] { 9, 7, 5, 3, 1 }; // initialize a fixed array in C++11
char fixedArray[14] { "Hello, world!" }; // initialize a fixed array in C++11
One caveat, in C++11 you can not initialize a dynamically allocated char array from a C-style string:
char *array = new char[14] { "Hello, world!" }; // doesn't work in C++11
If you have a need to do this, dynamically allocate a std::string instead (or allocate your char array and then strcpy the string in).
Also note that dynamic arrays must be declared with an explicit length:
int fixedArray[] {1, 2, 3}; // okay: implicit array size for fixed arrays
int *dynamicArray1 = new int[] {1, 2, 3}; // not okay: implicit size for dynamic arrays
int *dynamicArray2 = new int[3] {1, 2, 3}; // okay: explicit size for dynamic arrays

you allocate memory using the new operator and release a pointer using delete operator. Note that you can't delete normal variables, only pointers and arrays can be deleted after accomplishing their task.
int * foo;
foo = new int [5];
delete[] foo;
a complete program
#include <iostream>
#include <new>
using namespace std;
int main ()
{
int i,n;
int * p;
cout << "How many numbers would you like to type? ";
cin >> i;
p= new (nothrow) int[i];
if (p == nullptr)
cout << "Error: memory could not be allocated";
else
{
for (n=0; n<i; n++)
{
cout << "Enter number: ";
cin >> p[n];
}
cout << "You have entered: ";
for (n=0; n<i; n++)
cout << p[n] << ", ";
delete[] p;
}
return 0;
}
result
How many numbers would you like to type? 5
Enter number : 75
Enter number : 436
Enter number : 1067
Enter number : 8
Enter number : 32
You have entered: 75, 436, 1067, 8, 32,

In C++ we have the methods to allocate and de-allocate dynamic memory.The variables can be allocated dynamically by using new operator as,
type_name *variable_name = new type_name;
The arrays are nothing but just the collection of contiguous memory locations, Hence, we can dynamically allocate arrays in C++ as,
type_name *array_name = new type_name[SIZE];
and you can just use delete for freeing up the dynamically allocated space, as follows,
for variables,
delete variable_name;
for arrays,
delete[] array_name;

You need to be extremely careful when using raw pointers with dynamic memory but here is a simple example.
int main() {
// Normal Pointer To Type
int* pX = nullptr;
pX = new int;
*pX = 3;
std::cout << *pX << std::endl;
// Clean Up Memory
delete pX;
pX = nullptr;
// Pointer To Array
int* pXA = nullptr;
pXA = new int[10]; // 40 Bytes on 32bit - Not Initialized All Values Have Garbage
pXA = new int[10](0); // 40 Bytes on 32bit - All Values Initialized To 0.
// Clean Up Memory To An Array Of Pointers.
delete [] pXA;
pXA = nullptr;
return 0;
} // main
To avoid memory leaks; dangling pointers, deleting memory to early etc. Try using smart pointers. They come in two varieties: shared and unique.
SomeClass.h
#ifndef SOME_CLASS_H
#define SOME_CLASS_H
class SomeClass {
private:
int m_x;
public:
SomeClass();
explicit SomeClass( x = 0 );
void setX( int x );
int getX() const;
private:
SomeClass( const SomeClass& c ); // Not Implemented - Copy Constructor
SomeClass& operator=( const SomeClass& c ); Not Implemented - Overloaded Operator=
}; // SomeClass
#endif // SOME_CLASS_H
SomeClass.cpp
#include "SomeClass.h"
// SomeClass() - Default Constructor
SomeClass::SomeClass() :
m_x( x ) {
} // SomeClass
// SomeClass() - Constructor With Default Parameter
SomeClass::SomeClass( int x ) :
m_x( x ) {
} // SomeClass
// setX()
void SomeClass::setX( int x ) {
m_x = x;
} // setX
// getX()
void SomeClass::getX() const {
return m_x;
} // getX
Old Way Of Using Dynamic Memory
#include <iostream>
#include "SomeClass.h"
int main() {
// Single Dynamic Pointer
SomeClass* pSomeClass = nullptr;
pSomeClass = new SomeClass( 5 );
std::cout << pSomeClass->getX() << std::endl;
delete pSomeClass;
pSomeClass = nullptr;
// Dynamic Array
SomeClass* pSomeClasses = nullptr;
pSomeClasses = new SomeClasses[5](); // Default Constructor Called
for ( int i = 0; i < 5; i++ ) {
pSomeClasses[i]->setX( i * 10 );
std::cout << pSomeSomeClasses[i]->getX() << std::endl;
}
delete[] pSomeClasses;
pSomeClasses = nullptr;
return 0;
} // main
The problem here is knowing when, where and why to delete memory; knowing who is responsible. If you delete the memory to manage it and the user of your code or library assumes you didn't and they delete it there is a problem since the same memory is trying to be deleted twice. If you leave it up to the user to delete it and they assumed you did and they don't you have a problem and there is a memory leak. This is where the use of smart pointers come in handy.
Smart Pointer Version
#include <iostream>
#include <memory>
#include <vector>
#include "SomeClass.h"
int main() {
// SHARED POINTERS
// Shared Pointers Are Used When Different Resources Need To Use The Same Memory Block
// There Are Different Methods To Create And Initialize Shared Pointers
auto sp1 = std::make_shared<SomeClass>( 10 );
std::shared_ptr<SomeClass> sp2( new SomeClass( 15 ) );
std::shared_ptr<SomeClass> sp3;
sp3 = std::make_shared<SomeClass>( 20 );
std::cout << "SP1: " << sp1->getX() << std::endl;
std::cout << "SP2: " << sp2->getX() << std::endl;
std::cout << "SP3: " << sp3->getX() << std::endl;
// Now If you Reach The Return Of Main; These Smart Pointers Will Decrement
// Their Reference Count & When It Reaches 0; Its Destructor Should Be
// Called Freeing All Memory. This Is Safe, But Not Guaranteed. You Can
// Release & Reset The Memory Your Self.
sp1.reset();
sp1 = nullptr;
sp2.reset();
sp2 = nullptr;
sp3.reset();
sp3 = nullptr;
// Need An Array Of Objects In Dynamic Memory?
std::vector<std::shared_ptr<SomeClass>> vSomeClasses;
vSomeClasses.push_back( std::make_shared<SomeClass>( 2 ) );
vSomeClasses.push_back( std::make_shared<SomeClass>( 4 ) );
vSomeClasses.push_back( std::make_shared<SomeClass>( 6 ) );
std::vector<std::shared_ptr<SomeClass>> vSomeClasses2;
vSomeClasses2.push_back( std::shared_ptr<SomeClass>( new SomeClass( 3 ) ) );
vSomeClasses2.push_back( std::shared_ptr<SomeClass>( new SomeClass( 5 ) ) );
vSomeClasses2.push_back( std::shared_ptr<SomeClass>( new SomeClass( 7 ) ) );
// UNIQUE POINTERS
// Unique Pointers Are Used When Only One Resource Has Sole Ownership.
// The Syntax Is The Same For Unique Pointers As For Shared Just Replace
// std::shared_ptr<SomeClass> with std::unique_ptr<SomeClass> &
// replace std::make_shared<SomeClass> with std::make_unique<SomeClass>
// As For Release Memory It Is Basically The Same
// The One Difference With Unique Is That It Has A Release Method Where Shared Does Not.
auto mp1 = std::make_unique<SomeClass>( 3 );
mp1.release();
mp1.reset();
mp1 = nullptr;
// Now You Can Also Do This:
// Create A Unique Pointer To An Array Of 5 Integers
auto p = make_unique<int[]>( 5 );
// Initialize The Array
for ( int i = 0; i < 5; i++ ) {
p[i] = i;
}
return 0;
} // main
Here Are Reference Links To Both Shared & Unique Pointers
https://msdn.microsoft.com/en-us/library/hh279669.aspx
https://msdn.microsoft.com/en-us/library/hh279676.aspx

Related

Size of an object without using sizeof in C++

This was an interview question:
Say there is a class having only an int member. You do not know how many bytes the int will occupy. And you cannot view the class implementation (say it's an API). But you can create an object of it. How would you find the size needed for int without using sizeof.
He wouldn't accept using bitset, either.
Can you please suggest the most efficient way to find this out?
The following program demonstrates a valid technique to compute the size of an object.
#include <iostream>
struct Foo
{
int f;
};
int main()
{
// Create an object of the class.
Foo foo;
// Create a pointer to it.
Foo* p1 = &foo;
// Create another pointer, offset by 1 object from p1
// It is legal to compute (p1+1) but it is not legal
// to dereference (p1+1)
Foo* p2 = p1+1;
// Cast both pointers to char*.
char* cp1 = reinterpret_cast<char*>(p1);
char* cp2 = reinterpret_cast<char*>(p2);
// Compute the size of the object.
size_t size = (cp2-cp1);
std::cout << "Size of Foo: " << size << std::endl;
}
Using pointer algebra:
#include <iostream>
class A
{
int a;
};
int main() {
A a1;
A * n1 = &a1;
A * n2 = n1+1;
std::cout << int((char *)n2 - (char *)n1) << std::endl;
return 0;
}
Yet another alternative without using pointers. You can use it if in the next interview they also forbid pointers. Your comment "The interviewer was leading me to think on lines of overflow and underflow" might also be pointing at this method or similar.
#include <iostream>
int main() {
unsigned int x = 0, numOfBits = 0;
for(x--; x; x /= 2) numOfBits++;
std::cout << "number of bits in an int is: " << numOfBits;
return 0;
}
It gets the maximum value of an unsigned int (decrementing zero in unsigned mode) then subsequently divides by 2 until it reaches zero. To get the number of bytes, divide by CHAR_BIT.
Pointer arithmetic can be used without actually creating any objects:
class c {
int member;
};
c *ptr = 0;
++ptr;
int size = reinterpret_cast<int>(ptr);
Alternatively:
int size = reinterpret_cast<int>( static_cast<c*>(0) + 1 );

Destructor causes corruption of the heap.

I'm playing around with destructors and I don't understand why I get an error for this code when the main function terminates.
#include <iostream>
#include <math.h>
#include <string>
#include <cstdint>
#include <cassert>
using namespace std;
class RGBA {
uint8_t _red, _blue, _green, _alpha;
int *_arr;
int _length;
public:
RGBA(int *arr, int length, uint8_t r = 0, uint8_t b = 0, uint8_t g = 0, uint8_t a = 255):
_red (r), _blue (b), _green (g), _alpha (a) {
_arr = arr;
_length = length;
}
~RGBA() {
cout << "Destroying object" << endl;
delete[] _arr;
}
void print() {
for (int i = 0; i < _length; ++i) {
cout << _arr[i] << endl;
}
cout << static_cast<int>(_red) << " " << static_cast<int>(_blue) << " " << static_cast<int>(_green) << " " << static_cast<int>(_alpha) << endl;
}
};
int main() {
int arr[3] = {1,2,3};
RGBA rgba(arr, 3);
rgba.print();
cin.get();
return 0;
}
It outputs, but then when I press Enter, it prints 'Destroying object' with the following error "This may be due to a corruption of the heap, which indicates a bug in testcpp.exe or any of the DLLs it has loaded.".
1
2
3
0 0 0 255
I use VS2010 on Win7.
The automatic storage duration variable int arr[3] will be automatically deallocated when the enclosing function exits.
Trying to delete[] it causes undefined behavior. Only objects allocated with new[] can be deallocated with delete[].
In your case, this is effectively what is happening:
int arr[3] = {1,2,3};
delete[] arr;
Your arr in main is in automatic storage. You pass it into your object, which assumes ownership and assumes the memory was dynamically allocated with new.
You should only delete [] what you new [].
~RGBA() {
cout << "Destroying object" << endl;
delete[] _arr;
}
Here was your problem because delete didn't work on static array, It always work for dynamic array. delete only work for new
int *arr = new int[3];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
this will work perfectly.
The array you are passing, arr is being allocated on the stack in your main function. You then pass the pointer to your RGBA instance which then deletes the array in its destructor. As it was not dynamically allocated in the first place, this is a bad thing.
Deleting the array in the destructor indicates that you mean to transfer ownership of the array to that class. To do that, you need to either pass a dynamically allocated array or allocate a new array in the constructor and copy the contents of the one passed by parameter.
If you do not need ownership, simply remove the delete call in the destructor.
That's because you aren't supposed to delete the array.
The implementation of your destructor is correct, but the array is not allocated with new[], so you must not de-allocating with delete[].
If you'd replace your array in your main with it's modernized cousin, std::array, and the pointer in your class by std::vector, you would see that assigning a array to a vector would require an allocation on the heap and a copy of each element in your array.
A quick way to fix the code would be to allocate the array using new[]:
int* arr = new int[3]{1, 2, 3};
RGBA rgba(arr, 3);
rgba.print();
Now that the array is allocated using new[], it can be safely deleted using delete[].
However, please note that in most modern code, you either use std::array<T, N>, std::vector<T> or std::unique_ptr<T[]> to manage arrays.
The resulting code that use arrays and vectors would be like this:
#include <iostream>
#include <vector>
#include <array>
struct RGBA {
std::uint8_t red = 0, green = 0, blue = 0, alpha = 255;
std::vector<int> arr;
RGBA(std::vector<int> _arr) : arr{std::move(_arr)} {}
// No destructor needed. vector manages it's own resources.
void print() {
for (auto&& number : arr) {
std::cout << number << std::endl;
}
std::cout << static_cast<int>(red) << " "
<< static_cast<int>(blue) << " "
<< static_cast<int>(green) << " "
<< static_cast<int>(alpha) << std::endl;
}
};
int main() {
// Create a constant array on the stack the modern way
constexpr std::array<int, 3> arr{1, 2, 3};
// Copy array elements in the vector
RGBA rgba{std::vector<int>{arr.begin(), arr.end()}};
rgba.print();
cin.get();
}

unique_ptr with array crash when calling reset

Can someone explain the crash here?
#include <iostream>
#include <memory>
int main() {
int *num1 = new int(5), *num2 = new int(18);
std::unique_ptr<int> numptr = std::unique_ptr<int>(num1);
std::cout << *numptr.get() << '\n'; // 5
numptr.reset(num2);
std::cout << *numptr.get() << '\n'; // 18
int a[5] = {0,2,4,6,8}, b[5] = {0,3,6,9,12};
std::unique_ptr<int[]> u = std::unique_ptr<int[]>(a);
std::cout << u[3] << '\n'; // 6
u.reset(b);
std::cout << u[3] << '\n'; // Crash. Why??? Should output 9, right?
}
There is no crash when calling reset with std::unique_ptr<int>, so why the crash with std::unique_ptr<int[]>. As I see it, u takes ownership of b, and then deletes a. So u[3] should be b[3] = 9 which should work fine because b is not deleted. What's going on here?
You wrap your unique_ptr around an array, which has automatic storage duration and its memory will be released by the runtime. At the end of your program, unique_ptr tries to release the same memory. Basically the line u.reset(b); is equivalent to delete[] a; // then set u to point to b.
If you try a simple program like
int main()
{
int arr[10];
delete[] arr; // runtime error here
}
you'll get exactly the same error. You should never use smart pointers with non-dynamic objects.

Dynamically Allocated Array of Struct Pointers in C++

Ok i'm pretty new to c++ (I think what we are learning is somehow an hybrid of c and c++).
I've found alot of anwsers to my question, sadly all of them where in C using malloc.
struct A {
int randomStuff = 0;
};
struct B {
int numOfA= 5; // In reality this number is variable.
A** arrayOfA;
};
The struct are given to us. Now I need to allocate and fill this array with pointers to, I guess, A pointers. <- Correct me here if I'm wrong pointers are still quite complex for me.
A * a1 = new A;
A * a2 = new A;
B * b = new B;
// Allocate space for the array...
b->arrayOfA = new A*[numOfA];
// Next I want to initialize the pointers to NULL
for(int i; i < b->numOfA; i++){
b->arrayOfA[i] = NULL;
}
// In another function I would the assign a value to it
b->arrayOfA[0] = a1;
b->arrayOfA[1] = a2;
The way I see it is that b->arrayOfA needs to point to an array of A struct...somehow like this
b->arrayOfA = new A*;
A * arr[numOfA];
b->arrayOfA = arr;
My brain is bleeding.
How do I correctly allocate it and assign existing values(A structs) to it?
*edit
It would appear that the code was working as intended and that my display was causing me issues. Basically, I needed an array "arrayOfA[]" in which I would put the pointers to an A struct. Effectively making the result of this:
cout << arrayOfA[0]->randomStuff // 0 would be displayed
To be 0.
You could allocate an array of pointers and for each of them allocate an array of your objects
int x = 5, y = 6;
b->arrayOfA = new A*[x]; //array of pointers
for(int i=0;i<x;i++){
b->arrayOfA[i] = new A[y]; //matrix (array of arrays)
}
for(int i=0;i<x;i++){
delete[] b->arrayOfA[i]; //don't forget to free memory
}
delete[] b->arrayOfA;
You should be able to just use a vector:
#include <vector>
int main()
{
vector<A> vector_of_a;
vector_of_a.push_back(a1); //store a1 in the vector
vector_of_a.push_back(a2); //store a2 in the vector
//...
std::cout << "Number of A's: " << vector_of_a.size() << std::endl;
std::cout << vector_of_a[0].randomStuff << std::endl; //prints 0 as specified but with '.' not '->' Objects are still on the heap, and not the stack.
}
The A's in the vector are stored on the heap, but you don't need to manage the memory yourself (no need for malloc/free or new/delete.
The A objects will be disposed of correctly when the vector goes out of scope.
You also get
You can push in pointers to objects too, but this reduces the usefulness of the vector as you then have to do your own memory management for the objects:
#include <vector>
int main()
{
A* a1 = new A();
A* a2 = new A();
vector<A> vector_of_a;
vector_of_a.push_back(a1); //store pointer to a1 in the vector
vector_of_a.push_back(a2); //store pointer to a2 in the vector
//...
std::cout << "Number of A's: " << vector_of_a.size() << std::endl;
std::cout << vector_of_a[0]->randomStuff << std::endl; //prints 0 as specified
//...
for (auto i : vector_of_a)
{
delete (i);
}
vector_of_a.clear();
}
If you really don't want to use a vector, then I reccommend turning your struct B into a fully fledged class.
It gives you the benefit of encapsulation, functions to manage the data are stored within the class, and the class does the memory management and doesn't leave it to the
user's code to manage and clear up behind it:
class B
{
public:
array_of_A(unsigned int size);
~array_of_A();
bool init_array();
unsigned int get_size();
A** get_array();
private:
unsigned int num_of_A;
A** array_of_A;
}
B::array_of_A(unsigned int size)
{
num_of_a = size;
array_of_A = new A*[size]; //create array
memset (array_of_A, nullptr, size); //initialise contents to nullptr
}
B::~B()
{
for(unsigned int i = 0; i < num_of_a; i++)
{
delete array_of_a[i]; //delete each A
}
delete[](array_of_a); //delete the array of pointers.
}
unsigned int B::get_size()
{ return num_of_A; }
A** B::get_array()
{ return array_of_A; }
int main()
{
B b((5)); //most vexing parse...
b.get_array()[0] = new A();
b.get_array()[1] = new A();
b.get_array()[2] = new A();
std::cout << b.get_array()[0]->randomStuff << std::endl //prints 0 as requested
} //b goes out of scope, destructor called, all memory cleaned up
aaaand by internalising the memory management and supporting arbitarilly long arrays, we've just started implementing a (much) simpler version of vector. But good for practice/learning.

A bunch of unclear things with the destructor in C++

I've written some very simple code in C++ to do some simple manipulations of vectors. This is the content of the file vector.h:
#ifndef VECTOR_H_INCLUDED
#define VECTOR_H_INCLUDED
class Vector {
int *coordinates;
int *size;
public:
Vector(int vector_size);
Vector(int*,int);
~Vector();
void print(void);
Vector operator +(Vector);
};
#endif
and this is the implementation (file: vector.cpp):
#include "vector.h"
#include <iostream>
using namespace std;
Vector::Vector(int vector_size) {
coordinates = new int[vector_size];
size = new int;
*size = vector_size;
}
Vector::Vector(int* vector_coordinates, int vector_size){
coordinates = vector_coordinates;
size = new int;
*size = vector_size;
}
void Vector::print(void){
cout << "[";
for (unsigned short int index =0; index<*size; index++){
cout << coordinates[index];
if (index < *size-1){cout << ", ";};
}
cout << "]\n";
}
Vector Vector::operator+ (Vector other) {
Vector temp(*(other.size));
if ((*temp.size)!=(*(this->size))){
throw 100;
}
int* temp_c = new int[*(other.size)];
int* other_c = other.coordinates;
for (unsigned short int index =0; index<*size; index++){
temp_c[index] = coordinates[index] + other_c[index];
}
temp.coordinates = temp_c;
return (temp);
}
Vector::~Vector(){
delete[] coordinates;
delete size;
}
From my main.cpp, I do the following:
#include <iostream>
using namespace std;
#include "vector/vector.h"
const int size = 3;
int main() {
int *xxx = new int[size];
xxx[0]=4; xxx[1]=5; xxx[2]=-6;
Vector v(xxx,size);// v = [4, 5, -6]
Vector w(size);// w is a vector of size 3
w = v+v; // w should be w=[8,10,-12]
w.print();
return 0;
}
The result is then:
[148836464, 5, -6, 17, 148836384, 0, 0, 17, 0, 0, 0, 17, 3, 0, 0, 17, 0, 0, 0, 17, 148836480, 0, 0, 17, 0, 10, -12, 135025, 0, 0, 0, 0, 0, 0, , 0, 0,Segmentation fault
If I remove the two lines from the destructor:
delete[] coordinates;
delete size;
everything works as expected and the program outputs:
[8, 10, -12]
I would appreciate any explanations...
Update 1: I changed my operator+ method to the following, but the problem was not resolved:
Vector Vector::operator+(Vector other) {
int size_of_other = *(other.size);
int size_of_me = *(this->size);
if (size_of_other != size_of_me) {
throw 100;
}
int* temp_c = new int[size_of_me];
int* other_c = other.coordinates;
for (unsigned short int index = 0; index < size_of_me; index++) {
temp_c[index] = coordinates[index] + other_c[index];
}
Vector temp(temp_c,size_of_me);
return (temp);
}
Update 2: I noticed that using the operator:
Vector Vector::operator+(Vector other);
I wouldn't get the desired result. The modification that made it work was:
const Vector& Vector::operator+(const Vector& other) {
Vector temp(other.size);
for (unsigned short int index = 0; index < size; index++) {
cout << "("<< index <<") "<<coordinates[index] << "+"
<<other.coordinates[index] << ", "<< endl;
temp.coordinates[index] = coordinates[index] + other.coordinates[index];
}
return (temp);
}
Update 3: After update #2, I was getting a warning from the compiler that I return the local 'temp'. I changed my code to the following which completely resolved all problems and works fine (I return a copy of temp):
const Vector Vector::operator+(const Vector& other) const{
Vector temp(other.size);
for (unsigned short int index = 0; index < size; index++) {
temp.coordinates[index] = coordinates[index] + other.coordinates[index];
}
return *(new Vector(temp));
}
Your Vector::operator+ has at least one bug:
int* temp_c = new int;
...
temp_c[index] =
You are indexing temp_c when it was allocated with only a single integer. So your loop is stomping on some other memory, causing undefined behaviour.
You will also need to define a copy constructor so that you can properly use your Vector objects. The compiler generates a default copy constructor, but the default one is generally not suitable for objects that contain pointers.
This line:
temp.coordinates = temp_c;
causes a memory leak, because it overwrites the previously allocated temp.coordinates vector.
Update 3: Your code
return *(new Vector(temp));
while it appears to work, is still a memory leak. You are allocating a new Vector, then the compiler calls the copy constructor to copy that into the return value of your function. Nobody ever deletes the Vector object you just created, so there is a memory leak.
The solution is to write a copy constructor, instead of relying on the compiler-generated default copy constructor. All the other answers to your question have said the same thing. It is required that you do this for a correct program.
Your class needs a copy constructor and copy assignment operator to work correctly. A big hint that they are needed is that the destructor is not {}. See the "Rule of Three".
To get a bit better and more modern, you could also consider a move constructor and move assignment operator.
Try the code below which:
Implements a default constructor. This garauntees that however your object is constructed, your internal variables are going to be pointing at something on the heap or at NULL so any delete [] calls aren't going to die horribly.
Implements a copy constructor. Default copy constructors don't copy memory on the heap so that was going to be a serious problem for you.
Implements an assignment operator. Again this avoids shallow copies.
Removes size as a pointer; On most systems, pointers are the same size as integers so making size a pointer just makes things unnecessarily complicated.
Fixes the addition constructor by avoiding intermediate allocations. You had a temporary local variable there so make use of it instead of allocating several extra intermediate objects.
...take a look:
// VectorImplementation.cpp : Defines the entry point for the console application.
//
#include <iostream>
using namespace std;
class Vector {
int *coordinates;
int size;
public:
Vector();
Vector(int vector_size);
Vector(int*,int);
Vector(const Vector& v);
~Vector();
Vector operator +(Vector);
Vector& operator =(const Vector & other);
void print(void);
};
Vector::Vector() {
coordinates = NULL;
size = NULL;
}
Vector::Vector(int vector_size) {
coordinates = new int[vector_size];
size = vector_size;
}
Vector::Vector(int* vector_coordinates, int vector_size){
coordinates = vector_coordinates;
size = vector_size;
}
Vector::Vector(const Vector& v) {
size = v.size;
coordinates = new int[size];
memcpy(coordinates,v.coordinates, sizeof(int)*size);
}
void Vector::print(void){
cout << "[";
for (unsigned short int index =0; index<size; index++){
cout << coordinates[index];
if (index < size-1){cout << ", ";};
}
cout << "]\n";
}
Vector Vector::operator+ (Vector other) {
Vector temp(other.size);
for (unsigned short int index =0; index<size; index++){
temp.coordinates[index] = coordinates[index] + other.coordinates[index];
}
return (temp);
}
Vector & Vector::operator= (const Vector & other)
{
if (this != &other) // protect against invalid self-assignment
{
// 1: allocate new memory and copy the elements
int * tmp_coordinates = new int[other.size];
memcpy(tmp_coordinates, other.coordinates, sizeof(int)*other.size);
// 2: deallocate old memory
delete [] coordinates;
// 3: assign the new memory to the object
coordinates = tmp_coordinates;
size = other.size;
}
// by convention, always return *this
return *this;
}
Vector::~Vector(){
printf("Destructing %p\n", this);
delete[] coordinates;
}
const int size = 3;
int _tmain(int argc, _TCHAR* argv[])
{
int *xxx = new int[size];
xxx[0]=4;
xxx[1]=5;
xxx[2]=-6;
Vector v(xxx,size);// v = [4, 5, -6]
Vector w(size);// w is a vector of size 3
w = v+v; // w should be w=[8,10,-12]
w.print();
return 0;
}
Doing that is a bad idea:
Vector::Vector(int* vector_coordinates, int vector_size){
coordinates = vector_coordinates;
size = new int;
*size = vector_size;
}
you assign coordinates pointer to data that you did not allocate, and then try to delete it in the destructor.
But the real reason that you get segfault is that you use the default copy constructor, and the temporary copy of v deletes the vector when it dies. You have to implement copy constructor and ensure deep copy or reference counting.
Try something like this:
Vector::Vector(const Vector& other){
size = new int(*other.size);
coordinates = new int[size];
memcpy(coordinates, other.coordinates, sizeof(int)*(*size));
}
Also, your operator+ would be much more efficient if you take const reference as an argument:
Vector Vector::operator+ (const Vector& other)
Consider the line
w = v+v; // w should be w=[8,10,-12]
a temporary object is constructed for the result of v+v, then assigned to w and destroyed.
Since you don't have and assignment operator a shallow copy is performed by the default implementation and you are working with deallocated memory.
The simple way to fix this issue is to implement a copy constructor/ assignment operator and destructor when you are allocating memory for members.