I am trying to initialize my MedList but it's not working. Here's what I'm talking about:
repository.h
#include "../domain/farmacy.h"
#include "../utils/DynamicVector.h"
class Repository{
private:
DynamicVector<Medicine>* MedList; //I made it pointer so it can be dynamic
public:
Repository(); //constructor
repository.cpp
#include "../domain/farmacy.h"
#include "repository.h"
#include "../utils/DynamicVector.h"
#include <stdlib.h>
Repository::Repository(){
this->MedList=new DynamicVector<Medicine>::DynamicVector(); //error
}
DynamicVector.h
template <typename Element> //this is the Dynamic Vector constructor
DynamicVector<Element>::DynamicVector()
{
this->cap=10;
this->len=0;
this->elems=new Element[this->cap];
}
the error above is:
Multiple markers at this line
- no match for 'operator=' in '((Repository*)this)->Repository::MedList = (int*)operator
new(4u)'
- expected type-specifier
- candidate is:
- expected ';'
this is the medicine class
class Medicine{
private:
int ID;
std::string nume;
double concentratie;
int cantitate;
The Dynamic Vector class:
template <typename Element>
class DynamicVector{
private:
Element* elems;
int cap;
int len;
void resize();
void CopyToThis(const DynamicVector& v);
public:
DynamicVector(); //constructor implicit
DynamicVector(const DynamicVector& ); //constructor de copiere
DynamicVector& operator=(const DynamicVector& );
~DynamicVector();
void addElement(Element elem);
Element delElementAtPosition(int pos);
Element getElementAtPosition(int pos);
int getLen();
};
What am I doing wrong? I tried a lot of variants but nothing seems to work. Could you help me?
I think you're confusing c++ syntax for creating object with some other language, e.g. Java or C#.
In c++, a constructor is called simply by declaring the variable:
DynamicVector<Element> medList; // Calls DynamicVector<Element>::DynamicVector()
The new operator in C#, is to dynamically allocate space for a variable, and returns a pointer to the allocated space. To use it here, you'd have to declare Repository::MedList as a pointer type, and initialize it like so:
DynamicVector<Medicine>* MedList; // in repository.h
this->MedList = new DynamicVector<Medicine>(); // in repository.cpp
However, as Andy Prowl pointed out, it is much better to just let the compiler do the memory management for you. To do so, you should completely remove the erroneous line in repository.cpp. Why? Well, when the repository is constructed, the compiler also tries to construct all member objects using their default constructors. This is exactly what you want, so there is no reason to try to alter the compiler's behavior.
Constructor should be:
Repository::Repository(){
this->MedList=new DynamicVector<Medicine>;
}
DynamicVector() calls the constructor for DynamicVector.
DynamicVector::DynamicVector() is a pointer to the address of the constructor function
The chances are your C++ version doesn't allow empty () for constructors.
this->MedList=new DynamicVector<Medicine>::DynamicVector(); //error
should be
this->MedList=new DynamicVector<Medicine>::DynamicVector;
or (The usual way of writing it)
this->MedList=new DynamicVector<Medicine>;
See here for more info.
EDIT. Make sure you have declared the dynamicVector constructor in the class.
Default constructor with empty brackets
Do the parentheses after the type name make a difference with new?
Related
What are good practice options for passing around objects in a program, avoiding accessing non initialized member variables.
I wrote a small example which I think explains the problem very well.
#include <vector>
using namespace std;
class container{public:container(){}
vector<int> LongList;
bool otherInfo;
};
class Ship
{
public:Ship(){}
container* pContainer;
};
int main()
{
//Create contianer on ship1
Ship ship1;
ship1.pContainer = new container;
ship1.pContainer->LongList.push_back(33);
ship1.pContainer->otherInfo = true;
Ship ship2;
//Transfer container from ship1 onto ship2
ship2.pContainer = ship1.pContainer;
ship1.pContainer = 0;
//2000 lines of code further...
//embedded in 100 if statements....
bool info = ship1.pContainer->otherInfo;
//and the program crashes
return 0;
}
The compiler cannot determine if you are introducing undefined behavior like shown in your example. So there's no way to determine if the pointer variable was initialized or not, other than initializing it with a "special value".
What are good practice options for passing around objects in a program, avoiding accessing non initialized member variables.
The best practice is always to initialize the pointer, and check before dereferencing it:
class Ship {
public:
Ship() : pContainer(nullptr) {}
// ^^^^^^^^^^^^^^^^^^^^^
container* pContainer;
};
// ...
if(ship1.pContainer->LongList) {
ship1.pContainer->LongList.push_back(33);
}
As for your comment:
So there are no compiler flags that could warn me?
There are more simple and obvious cases, where the compiler may leave you with a warning:
int i;
std::cout << i << std::endl;
Spits out
main.cpp: In functin 'int main()':
main.cpp:5:18: warning: 'i' is used uninitialized in this function [-Wuninitialized]
std::cout << i << std::endl;
^
See Live Demo
One good practice to enforce the checks is to use std::optional or boost::optional.
class Ship
{
public:
Ship() : pContainer(nullptr) {}
std::optional<container*> Container()
{
if(!pContainer)
return {};
return pContainer;
}
private:
container* pContainer;
};
It will force you (or better: provide a firm reminder) to check the result of your getter:
std::optional<container*> container = ship1.Container();
container->otherInfo; // will not compile
if(container)
(*container)->otherInfo; // will compile
You would always need to check the result of operation if you use pointers. What I mean is that with optional the situation is more explicit and there's less probability that you as the programmer will forget to check the result.
It seems that you are looking for a way to make your code
bool info = ship1.pContainer->otherInfo;
work even though the pContainer may be null.
You can use a sentinel object, which holds some default data:
container default_container;
default_container.otherInfo = false; // or whatever the default is
Then use a pointer to the sentinel object instead of a null pointer:
//Transfer container from ship1 onto ship2
ship2.pContainer = ship1.pContainer;
ship1.pContainer = &default_container; // instead of 0
//2000 lines of code further...
//embedded in 100 if statements....
bool info = ship1.pContainer->otherInfo;
If you use this, you should make sure the sentinel object cannot be destroyed (e.g. make it a static member, or a singleton).
Also, in the constructor, initialize your pointers so they point to the sentinel object:
class Ship
{
public: Ship(): pContainer(&default_container) {}
...
};
I found an additional solution. It is admittedly not preventing the access of uninitialized objects, but at least the program crashes AND returns an error message, that enables us to correct our mistake. (This solution is particularly for the g++ compiler.)
First of all set the compiler flag _GLIBCXX_DEBUG. Then instead of naked pointer use unique_ptr.
#include <vector>
#include <iostream>
#include <memory>
using namespace std;
class container{
public:container(){}
int otherInfo = 33;
};
class Ship
{
public:Ship(){}
std::unique_ptr<container> upContainer;
};
int main()
{
Ship ship1;
cout<<ship1.upContainer->otherInfo<<endl;
return 0;
}
This code will produce an error:
std::unique_ptr<_Tp, _Dp>::pointer = container*]: Assertion 'get() != pointer()' failed.
Hence telling us that we should probably include an if(ship1.upContainer) check.
What are good practice options for passing around objects in a program, avoiding accessing non initialized member variables.
Good practice would be to initialize everything in the constructor.
Debatable better practice is to initialize everything in the constructor and provide no way of modifying any members.
Sorry for the confusing title, basically I have created two classes, one is an object, and the other being a box that contains an array of such objects. so what I want to do is create a function/constructor inside the object class that takes in an array of ints and stores them inside the box. I want to be able to call this function through the box class constructor to initialize these objects. So ive tried something like below but it isnt working at all, since only the first value of the array gets passed through. What am I doing wrong?
#include <iostream>
#include <string>
class object{
string objectName;
int values[];
public:
void createObject(int[]);
}
class Box{
object objects[100];
public:
Box();
}
Box::Box (void){
int array1[2];
int array2[15];
object[1].createObject(array1);
object[2].createObject(array2);
}
Object::Object(int Values[]){
values = Values;
}
You should really use std::vector. The problem with arrays is that they decay to pointers when passed as arguments to functions. As a consequence, If you want to store a private copy of the elements you are forced to use heap-allocated objects and consequently do memory management by hand (with all the pain it causes).
It is much better to rely on data members that permit applying the rule of zero.
Here's a tentative solution:
#include <iostream>
#include <string>
#include <vector>
class object {
public:
object(std::vector<int> const& v, std::string const& object_name): v_(v.begin(), v.end()), object_name_(object_name) {}
private:
std::vector<int> v_;
std::string object_name_;
};
class box {
public:
box(std::vector<object> const& objects): objects_(objects) {};
private:
std::vector<object> objects_;
};
I recommend you instead use a std::vector. Arrays don't really work well being passed to functions. When you define Object::Object(int Values[]) you are simply passing the first element of this array by value. If you were to use vectors, the function would look like this:
Object::Object(std::vector<int> &Values):
values(Values)
{
}
The problem with the code is in your thinking on what the array is. In C++, all an array is, is a memory pointer. The language allows you to pass an index into the array pointer to access whatever chunk of data lives at that index.
Whenever you pass arrays between functions or classes, pass the array name only. It will be interpreted as a pointer, and won't copy any data. When you do this, you must also pass the length of the array.
Granted, most people stick with vector<> because it's easier, takes care of memory leaks (mostly) and is VERY efficient. But I like doing it myself. It's good for you. I would try:
#include <iostream>
#include <string>
class Object
{
string _objectName;
int *_values;
int _myLength;
Object();
~Object();
void createObject(int *pValues, int arrLength);
}
class Box
{
_Object objects[100];
Box();
}
Box::Box(void) {
int array1[2];
int array2[15];
object[1].createObject(array1, 2);
object[2].createObject(array2, 15);
}
Object::Object() {
_values = null_ptr;
_myLength = 0;
}
Object::~Object() {
delete[] _values;
}
void Object::createObject(int *pvalues, int arrLength) {
_myLength = arrLength;
_values = new int[_myLength];
for(int ndx=0; ndx<arrLength; ndx++) {
_values[ndx] = pvalues[ndx];
}
}
-CAUTION-
I just adapted your code you provided, and added some conventions. There are a couple places in the code where I'm not sure what the purpose is, but there you go. This should give you a good head start.
This question already has answers here:
Destructor is called when I push_back to the vector
(4 answers)
Closed 8 years ago.
I noticed something here in this code . even if when push back the elements in vector (see function passtoit). Destructor of struct test is being called . can anyone please explain this to me .. why this behavior is there ...
when i declare the std::vector of static object and let it run it gives me that heap corruption problem and when i declare the test as std::vector of test pointer(*) and delete that pointer as shown in the commented code , it works fine. please explain . it will help me alot . i don't know what else to write here in order to make the stackworkflow understand that it is valid question
#include "stdafx.h"
#include <vector>
#include <iostream>
#include <vld.h>
using namespace std;
class declaration
class testHelper
{
public:
testHelper(int passed):m(passed){}
int m;
~testHelper(){cout<<"deleting as thought";}
};
declaration of structure
struct test
{
// constructor
test(string name,testHelper* help):name(name),dummy(help){}
string name;
testHelper *dummy;
// destructor
~test()
{
cout<<"deleting dummy";
if(dummy!=NULL)
{
delete dummy;
dummy =NULL;
}
}
};
function to pass
int passtoit()
{
std::vector<test> x;
// push back on the vector
x.push_back(test("prakash",(new testHelper(10))));
//for(std::vector<test>::iterator i =x.begin();i!=x.end();++i)
//{
// delete *i;
//}
return 0;
}
main function
int _tmain()
{
// calling the function
passtoit();
return 0;
}
When using std::vector<test>, elements are copied into the vector.
x.push_back(test("prakash",(new testHelper(10))));
You are creating an instance which is copied then immediately destroyed.
When we insert elements to vector using push_back, copy constructor is called, then a temporary object is created for the arguement object and is then inserted to vector. Then the temporary object is destroyed/deleted.
To check how it actually works, try overriding the copy constructor in private scope of the class. push_back function will not be called and you will get compiler error.
First,when vector is desctructed,it destroys every elemment.
template<class _Ty> inline
void _Destroy(_Ty _FARQ *_Ptr)
{ // destroy object at _Ptr
_DESTRUCTOR(_Ty, _Ptr);
}
#define _DESTRUCTOR(ty, ptr) (ptr)->~ty()
Second,You should known when temporary objects are destroyed.
"All temporaries created as a result of expression evaluation are destroyed at the end of the expression statement (that is, at the semicolon), or at the end of the controlling expressions for for, if, while, do, and switch statements."
See this:
Temporary Objects
So,the reason for this is the memory pointed by dummy is deleted twice.
To avoid this,You should override operator=
test& operator=(const test& t)
{
if(this == &t)
return *this;
name = t.name;
dummy = new testHelper(*t.dummy);
return *this;
}
Hi everyboy :) I m pretty new on programming and especially on C++.
This is why I am trying to test some beginners functions like getters and setters with private variable which are, in fact, pointers. I m doing this tests for an assignement and i have to use enumeration too.
I got 0 compilation error but my test program is crashing when i m trying to set my private pointer with an enum type.
Here is my class "Slot": header file : Slot.hpp
#ifndef SLOT_H
#define SLOT_H
enum Pawn{YELLOW, RED};
class Slot
{
public:
Slot();
~Slot();
Slot(const Slot& slot_to_copy) {color = new Pawn(*(slot_to_copy.color));}
void setColor(Pawn);
Pawn getColor();
private:
Pawn *color;
};
#endif
Here is my source file: Slot.cpp:
#include <iostream>
#include "Slot.hpp"
using namespace std;
Slot::Slot() {color = NULL;}
Slot::~Slot() {}
void Slot::setColor(Pawn col)
{
*color = col;
}
Pawn Slot::getColor()
{
return *color;
}
And here is my main where I am testing the getter and the setter:
#include <iostream>
#include "Slot.hpp"
using namespace std;
int main()
{
Slot test;
test.setColor(YELLOW); // testing the setter
Pawn coin = test.getColor(); // testing the getter
if (coin == YELLOW)
cout <<"SUCCESS"<< endl;
return 0;
}
My problem is located on the setter function ...
Thank you in advance for your help, i already took 3 hours by trying to fix my problem and I cannot work on my assignement without this working correctly :/
Sorry for my approximate English by the way.
PS: I HAVE TO use pointer for that, because it is asked by my teacher and consist in the difficulty (or at least a part of it) of our programming assignement.
Your default constructor Slot() doesn't allocate space for the Pawn *color, so it'll just point to some random location in memory. When you write to it you'll write to this random location.
You can set it like this:
Slot::Slot() : color(new Pawn)
{}
Here we're using the member initializer list to set color to allocated memory before the body of the constructor is executed. It's conceptually the same as saying:
Slot::Slot()
{
color = new Pawn;
}
For integral types and pointers there's not much difference. However, if the member variables were class instances then the member variable initializer list is the only way to initialize classes that do not have a default constructor.
However, since enum is effectivly an int there's no point is using a pointer. Just declare it as:
Pawn color;
And get/set it like this:
void Slot::setColor(Pawn col)
{
color = col;
}
Pawn Slot::getColor()
{
return color;
}
You are not initializing the pointer in the default constructor. This means de-referencing it is undefined behaviour. You should make it point to something you can write to later:
Slot::Slot() : color(new Pawn()) { }
Note that having a class manage dynamically allocated resources means it has to do sensible things in its copy constructor, assignment operator, and destructor. See the rule of three.
The easiest solution in not to use a pointer at all:
....
private:
Pawn color;
Your color pointer is being assigned to something only in copy constructor, while in your main you are creating Slot using default constructor, that's why pointer stays uninitialized and behaviour of functions like setColor is undefined.
I have a basic C++ class .The header looks like this:
#pragma once
class DataContainer
{
public:
DataContainer(void);
~DataContainer(void);
int* getAgeGroup(void);
int _ageGroupArray[5];
private:
int _ageIndex;
};
Now inside the cpp file of the class I want to intialize the _ageGroupArray[5] with default values inside the class contructor like this:
#include "DataContainer.h"
DataContainer::DataContainer(void)
{
_ageGroupArray={20,32,56,43,72};
_ageIndex=10;
}
int* DataContainer::getAgeGroup(void){
return _ageGroupArray;
}
DataContainer::~DataContainer(void)
{
}
Doing it I am getting "Expression must be a modifiable lvalue" on _ageGroupArray line.So is it entirely impossible to initialize an array object in the constructor? The only solution I found was to define the array outside scope identifiers .Any clarification on this will be greatly appreciated.
In the current standard, as you have already noticed, you cannot initialize a member array in the constructor with the initializer list syntax. There are some workarounds, but none of them is really pretty:
// define as a (private) static const in the class
const int DataContainer::_age_array_size = 5;
DataContainer::DataContainer() : _ageIndex(10) {
int tmp[_age_array_size] = {20,32,56,43,72};
std::copy( tmp, tmp+_age_array_size, _ageGroupArray );
}
If the values in the array are always the same (for all object in the class) then you can create a single static copy of it:
class DataContainer {
static const int _ageGroupArraySize = 5;
static const int _ageGroupArray[ _ageGroupArraySize ];
// ...
};
// Inside the cpp file:
const int DataContainer::_ageGroupArray[_ageGroupArraySize] = {20,32,56,43,72};
You can Initialize a array when you Create/Declare it, not after that.
You can do it this way in constructor :
_ageGroupArray[0]=20;
_ageGroupArray[1]=32;
_ageGroupArray[2]=56;
_ageGroupArray[3]=43;
_ageGroupArray[4]=72;
It is important to know that this is Assignment & not Initialization.
try this:
int ageDefault[]={20,32,56,43,72};
memcpy(_ageGroupArray, ageDefault, sizeof(ageDefault));