I'm new with c++ and I've been meaning to implement vector calculations via operator overloading.
The code that's not functioning as I intended is this.
First, main.cpp
#include <iostream>
#include "MyVector.h"
#include "MyVector.cpp"
int main() {
double forvector1[] = {0.1,0.2,0.3};
double forvector2[] = {0.2,0.3,0.5};
MyVector vector1(forvector1,3);
MyVector vector2(forvector2,3);
MyVector temp = vector1 + vector2;
temp.print();
return 0;
}
Then, MyVector.cpp
#include "MyVector.h"
#include <iostream>
using namespace std;
MyVector::MyVector(double numList[], int size) : numList(numList), size(size) {
}
MyVector::MyVector(){ //empty vector;
}
void MyVector::print(){
cout<<"("<<numList[0];
for(int i=1;i<size;i++){
cout<<", "<<numList[i];
}
cout<<")"<<endl;
}
MyVector MyVector:: operator+(MyVector vec){
if(vec.size != size){
cout<<"+ cannot be applied to ";
cout<<"("<<numList[0];
for(int i=1;i<size;i++){
cout<<", "<<numList[i];
}
cout<<") and ";
vec.print();
return MyVector();
}
double tempList[size];
for(int i=0;i<size;i++)
{
tempList[i]=numList[i]+vec.numList[i];
}
MyVector result(tempList,size);
return result;
}
Finally, this is my MyVector.h
class MyVector{
private:
int size;
double * numList;
public:
MyVector(double numList[], int size); //size>=1
MyVector(); //empty Vector
void print(); //print its content e.g. (1, 2, 3, 4)
MyVector operator-(MyVector vec);
MyVector operator+(MyVector vec);
double operator*(MyVector vec);
MyVector operator/(MyVector vec);
//You may add more member functions as well
};
#endif // MYVECTOR_H_INCLUDED
According to the main.cpp, I should be getting (0.3, 0.5, 0.8) for the output. However, I keep getting (0.3, 0, 2.12199e-314), which means probably only the first element of the result array was right. I'm guessing it's because of the pointer I used to point at the array, so that's why only the first element was correct. Is there any way I could make the operator+ work? Any help would be appreciated. Thanks!
My guess would be that there is a dangling pointer.
double tempList[size];
for(int i=0;i<size;i++)
{
tempList[i]=numList[i]+vec.numList[i];
}
MyVector result(tempList,size);
return result;
tempList points to data that are local to the function, but result uses it. In your constructor, you should copy the data in the array into another array owned by the object.
Related
I'm quite new to programming (currently learning C++). I'm trying to learn how to use smart pointers.
I'm trying to do a challenge from a tutorial in which the goal is to fill in data points to a unique_ptr of a vector that contains shared_ptrs that points to a data point. When I run it, it shows 0 errors and 0 warnings so I'm a bit lost on what went wrong since it crashes when I start to add the data(int). Would really appreciate some help on what's going on with this code. I'm still confused on using smart pointers.
#include <iostream>
#include <memory>
#include <vector>
class Test {
private:
int data;
public:
Test():data(0) {std::cout<<"\tTest constructor ("<< data << ")"<<std::endl;}
Test(int data): data{data} {std::cout<< "\tTest constructor ("<< data << ")"<<std::endl;}
int get_data() const {return data;}
~Test(){std::cout<<"\tTest destructor ("<<data<<")"<<std::endl;}
};
//Function prototypes
std::unique_ptr<std::vector<std::shared_ptr<Test>>>make();
void fill(std::vector<std::shared_ptr<Test>> &vec, int num);
void display(const std::vector<std::shared_ptr<Test>>&vec);
std::unique_ptr<std::vector<std::shared_ptr<Test>>>make(){
return std::unique_ptr<std::vector<std::shared_ptr<Test>>>();
}
void fill(std::vector<std::shared_ptr<Test>> &vec, int num){
int temp;
for(int i=0; i<num; ++i){
std::cout<<"Enter the data points for ["<<i<<"]:";
std::cin>>temp;
std::shared_ptr<Test>p1 {new Test {temp}};
vec.push_back(p1);
}
}
void display(const std::vector<std::shared_ptr<Test>>&vec){
std::cout<<"--DISPLAYING VECTOR DATA--"<<std::endl;
for(const auto &i:vec)
std::cout<<i->get_data()<<std::endl;
}
int main() {
std::unique_ptr<std::vector<std::shared_ptr<Test>>> vec_ptr;
vec_ptr = make();
int num;
std::cout<<"How many data points do you want to enter: ";
std::cin >> num;
fill(*vec_ptr, num);
display(*vec_ptr);
return 0;
}
In the function make, return std::unique_ptr<std::vector<std::shared_ptr<Test>>>(); just returns an empty std::unique_ptr which owns nothing. Dereference and usage on it like *vec_ptr leads to undefined behavior.
You could
return std::unique_ptr<std::vector<std::shared_ptr<Test>>>(new std::vector<std::shared_ptr<Test>>);
Or better
return std::make_unique<std::vector<std::shared_ptr<Test>>>();
I wonder whether copying a vector I am copying the vector with its values (whereas this is not working with array, and deep copy need a loop or memcpy).
Could you hint to an explanation?
Regards
You are making a deep copy any time you copy a vector. But if your vector is a vector of pointers you are getting the copy of pointers, not the values are pointed to
For example:
std::vector<Foo> f;
std::vector<Foo> cp = f; //deep copy. All Foo copied
std::vector<Foo*> f;
std::vector<Foo*> cp = f; //deep copy (of pointers), or shallow copy (of objects).
//All pointers to Foo are copied, but not Foo themselves
Vector will resize to have enough space for the objects. It will then iterate through the objects and call the default copy operator for every object.
In this way, the copy of the vector is 'deep'. The copy of each object in the vector is whatever is defined for the default copy operator.
In examples... this is BAD code:
#include <iostream>
#include <vector>
using namespace std;
class my_array{
public:
int *array;
int size;
my_array(int size, int init_val):size(size){
array = new int[size];
for(int i=0; i<size; ++i)
array[i]=init_val;
}
~my_array(){
cout<<"Destructed "<<array[0]<<endl;
if(array != NULL)
delete []array;
array = NULL;
size = 0;
}
};
void add_to(vector<my_array> &container){
container.push_back(my_array(4,1));
}
int main(){
vector<my_array> c;
{
my_array a(5,0);
c.push_back(a);
}
add_to(c);
//At this point the destructor of c[0] and c[1] has been called.
//However vector still holds their 'remains'
cout<<c[0].size<<endl; //should be fine, as it copies over with the = operator
cout<<c[0].array[0]<<endl;//undefined behavior, the pointer will get copied, but the data is not valid
return 0;
}
This is BETTER code:
#include <iostream>
#include <vector>
using namespace std;
class my_array{
public:
int *array;
int size;
my_array(int size, int init_val):size(size){
cout<<"contsructed "<<init_val<<endl;
array = new int[size];
for(int i=0; i<size; ++i)
array[i]=init_val;
}
my_array(const my_array &to_copy){
cout<<"deep copied "<<to_copy.array[0]<<endl;
array = new int[to_copy.size];
size = to_copy.size;
for(int i=0; i<to_copy.size; i++)
array[i]=to_copy.array[i];
}
~my_array(){
cout<<"Destructed "<<array[0]<<endl;
if(array != NULL)
delete []array;
array = NULL;
size = 0;
}
};
void add_to(vector<my_array> &container){
container.push_back(my_array(4,1));
}
int main(){
vector<my_array> c;
{
my_array a(5,0);
c.push_back(a);
}
add_to(c);
//At this point the destructor of c[0] and c[1] has been called.
//However vector holds a deep copy'
cout<<c[0].size<<endl; //This is FINE
cout<<c[0].array[0]<<endl;//This is FINE
return 0;
}
I am trying to swap the content in the arrays by swapping the pointers pointing to the two arrays.
My method is the same as what Daniel answered in this question: Swap arrays by using pointers in C++. But the difference is that my array will be a member in a class.
My code can be compiled successfully, but the output results are quite weird.
This is my header file:
#include <stdio.h>
#include <iostream>
class Map
{
public:
Map(int times); // Create an empty map (i.e., one with no key/value pairs)
int size(); // Return the number of key/value pairs in the map.
void dump();
void swap(Map &other);
int *retrieve();
void setptr(int *newptr);
private:
int *ptr;
int array_1[5];
};
Here is my implementation:
#include "Map.h"
#include <iostream>
using namespace std;
Map::Map(int times) {
for (int i = 0; i < 5; i++) {
array_1[i]=i*times;
}
ptr=array_1;
}
void Map::dump() {
ptr=array_1;
for (int i = 0; i < 5; i++) {
cout << *ptr << endl;
ptr++;
}
for (int i = 0; i < 5; i++) {
ptr--;
}
}
void Map::swap(Map &other) {
int *temp;
temp = this->ptr;
this->ptr = other.retrieve();
other.setptr(temp);
}
int *Map::retrieve() {
return ptr;
}
void Map::setptr(int *newptr) {
ptr=newptr;
}
Can anyone tell me what is wrong and how to implement it smartly?
The following code runs fine:
#include <stdio.h>
#include <iostream>
#include <conio.h>
using namespace std;
class Map
{
public:
Map(int times); // Create an empty map (i.e., one with no key/value pairs)
int size(); // Return the number of key/value pairs in the map.
void dump();
void swap(int &other);
int *retrieve();
void setptr(int *newptr);
private:
int *ptr;
int array_1[5];
};
Map::Map(int times){
for (int i=0;i<5;i++){
array_1[i]=i*times;
}
ptr=array_1;
}
void Map::dump(){
for (int i=0;i<5;i++)
{
cout<<ptr[i]<<endl;
}
}
void Map::swap(int &other){
int *temp;
temp=this->ptr;
this->ptr=&other;
other = *temp;
}
int *Map::retrieve(){
return ptr;
}
void Map::setptr(int *newptr){
ptr=newptr;
}
int main()
{
Map m(2);
Map n(3);
m.dump();
m.swap(*n.retrieve());
m.dump();
getchar();
}
1) Added a main function
2) Changed Swap function
But the problem that christopher pointed out will still persist i.e the pointer will point to an array in another object.
Edit: You probably need something like this:
void Map::swap(Map &other){
Map *temp;
temp=this;
*this = other;
other = *temp;
}
Map *Map::retrieve(){
return this;
}
Note: it is probably not elegant.
The problem with your design is that the pointer refers to an array in the same object.
Suppose you have to objects a and b. If you swap their pointers, a.ptr will point to b.array_1 which contains the data. reciprocally b.ptr will point to a.array1.
Unfortunately if one of the object -- say b -- gets destroyed (because it was a local object that goes out of scope, or for whatever reason) the pointer of the remaining object would point to an array which doesn't exist anymore. This is UB.
To solve your issue, you'd neet to allocate an array dynamically in the constructor. Get rid of array_1 completely:
Map::Map(int times){
ptr=new int[5]; // or better define a constant to avoid hard coded sizes
for (int i=0;i<5;i++){
ptr[i]=i*times;
}
}
Note that if you use pointers, you need to ensure the invarients on it. This means that you should define also the copy constructor and the assignment operator (to avoid the ptr to be blindly copied), as well as a destructor (to delete the dynamically allocated array).
P.S.: I suppose that you are learning C++ and are not yet familiar with vectors. These would avoid all the hassles here
Edit: if you experience your problem before any object is destroyed, it's because of a bad implementation of dump(): you increment the pointer there in, so that it will no longer point to the start of the array.
void Map::dump(){
for (int i=0;i<5;i++){
cout<<ptr[i]<<endl; // don't change ptr value !!
}
}
One simple trick to avoid such problems, is to systematically declare the member functions that are not supposed to change the state of the object as const:
class Map {
...
void dump() const;
...
}
Then the compiler issues an error if you try to accidentally change a member.
/This program is using template class. I don't know why but this program is throwing an error at run time related memory access violation. in below comments i will explain which line is causing this error./
#include<iostream>
using namespace std;
const int size =3;
template <class t="">
class vector
{
T* v;
public:
vector()
{
v=new T[size];
for(int i=0;i<size;i++)>
v[i]=0;
}
vector(T* a)
{
for(int i=0;i<size;i++)>
v[i]=a[i];
}
T operator*(vector &y)
{
T sum=0;
for(int i=0;i<size;i++)>
sum+=this->v[i] * y.v[i];
return sum;
}
void display(void)
{
for(int i=0;i<size;i++)>
{
cout<<v[i]<<"\t";
}
cout<<"\n";
}
};
int main()
{
int x[3]={1,2,3};
int y[3]={4,5,6};
vector<int> v1;
vector <int> v2;
v1=x; // This is causing an error
v2=y; // This is causing an error
//int R=v1*v2;
//cout<<"R = "<<R<<"\n";
cout<<"V1 = ";
v1.display();
cout<<"V2 = ";
v2.display();
cout<<"V1 x V2 = "<<v1*v2;
return 0;
}
It seems that the problem is in this constructor
vector(T* a)
{
for(int i=0;i<size;i++)>
v[i]=a[i];
}
You did not allocate memory for the array pointed by v.
2 Problems:
You are not initializing memory for your vector
You are calling the constructor incorrecly
To fix #1
vector(T* a)
{
v=new T[size];
for(int i=0;i<size;i++)>
v[i]=a[i];
}
To fix #2
int x[3]={1,2,3};
int y[3]={4,5,6};
vector<int> v1(x);
vector <int> v2(y);
the constructor vector(T * a) will get called and the member v is not initialized with anything. This causes undefined behavior. So to fix this you need to allocate in that constructor
vector(T* a)
{
v = new T[size];//this line is new
for(int i=0;i<size;i++)
v[i]=a[i];
}
My guess is there is no operator=(int []) defined for vector.
So in other words, compiler does not know what do you mean by v1=x when it comes to type int[] = vector<int>.
You are not calling the overloaded constructor there. So you either need to call it vector<int> v1(y); or implement vector::operator=(const T[] v);
I hope i got the types right
When calling the lines in question, the program is using a default assignment operator which is doing something that causes your violation. You need to implement this yourself, for example, this worked for me:
T& operator=(T const * a)
{
for(int i=0;i<size;i++)
v[i]=a[i];
return *this;
}
#include<iostream>
#include<vector>
using namespace std;
class t{
public:
t();
void updateSize();
int getSize();
void insert();
int get(int a);
private:
int size;
vector<int> v;
};
t::t(){
size =0;
}
void t::updateSize(){
size++;
}
int t::getSize(){
return size;
}
int t::get(int a){
return v[a];
}
void t::insert(){
v.push_back(size);
++size;
}
int main(){
t xa;
xa.insert();
xa.insert();
xa.insert();
xa.insert();
cout<<xa.get(3);//expect to output 3 but instead outputs 0
return 0;
}
this code is supposed to increment the size every time I call insert, and put an integer of with the value of that size in a vector at the same index of that size. But for some reason it does not put the updated size into my vector.
You're inserting 3 elements but you're reading the 4th (since the indexing is 0 based).
The program you posted will print "3". Proof read your code.