what's a good smart pointer to use for c++?? I want them for use in a vector of pointers....
smart pointers for c++
Collapse
X
-
This question doesn't really make sense.
What do you mean by the term "smart pointer"?
A vector of pointers to what?
What you should try to do is avoid using a vector of void pointers (void *). They may sound like a good idea but the strong typing of C++ is useful in ensuring a rigerously written working program. Using void * just gets round this.
So what are the pointers in your vector pointing at? Is it a specific type, like int, in which case you can use int *, or a class or structure in which case you can, again, just use a pointer to that class or structure.
Or do you need to point to a variety of different classes. In this case you should see if there is some sort of link between the classes that allows you to declare the structures in a hierarchy and declare you vector with pointers to the base class in the hierarchy.
If none of that will do the trick then you may have to declare a union, however since you will need to be able to tell which item in the union is the one in use then you will probably have to do something like declare an enum identifying the union member in use and a structure containing an enum and a union entry and the vector with pointers to this structure. -
yeah, the pointers in the vector are pointing to class objects. there are different constructors in the class to initialize class objects with a different number of pointers. but all objects being pointed to are essentially the same, yeah.
I can't ever delete any of the objects, and I think the problem lies with the pointers I use to new them. the pointers to the objects are shuffled around in the vectors quite a bit, and I'm not sure that the vector is the best at handling pointers...Comment
-
If it is always the same class why use pointers at all just have a vector of classes like so
Code:#include <string> #include <vector> #include <iostream> using namespace std; class Colour { private: string name; unsigned char red; unsigned char green; unsigned char blue; public: Colour() { name="black"; red = 0; green = 0; blue = 0; } Colour(char *n, unsigned char r, unsigned char g, unsigned char b ) { name=n; red = r; green = g; blue = b; } inline operator const char * (void) const { return name.c_str(); } unsigned long GetColour(void) { return ((unsigned long)red<<16)|((unsigned long)green<<8)|blue; } }; static void vectorWork(void) { int i; vector <Colour> v1; v1.resize(10); for(i=0; i<v1.size(); i++) { cout << i << ": " << (const char *)v1[i] << endl; } cout << endl; v1[0] = Colour("Red", 255, 0, 0); v1[1] = Colour("Green", 0, 255, 0); v1[2] = Colour("Blue", 0, 0, 255); v1[3] = Colour("Cyan", 0, 255, 255); v1[4] = Colour("Magenta", 255, 255, 0); v1[5] = Colour("Yellow", 255, 0, 255); v1[6] = Colour("White", 255, 255, 255); v1[7] = Colour("Black", 0, 0, 0); v1[8] = Colour("Grey", 192, 192, 192); v1[9] = Colour("Dark Grey", 128, 128, 128); for(i=0; i<v1.size(); i++) { cout << i << ": " << (const char *)v1[i] << endl; } cout << endl; v1.erase( v1.begin( ) + 6, v1.begin( ) + 7 ); for(i=0; i<v1.size(); i++) { cout << i << ": " << (const char *)v1[i] << endl; } cout << endl; }Comment
-
ok, that didn't work, here it really is.
Code:#include "stdafx.h" #include <iostream.h> #include <fstream> #include <iomanip.h> #include <deque> #include <vector> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <math.h> #include <cassert> using namespace std; void main() { //initialize random number generator //srand(time(NULL)); srand(1247365); //variable to keep track of the total interbranch weight double TIBW = 0; //variable to keep track of the total number of interbranch spaces double IBC = 0; //variable to keep track of the number of generations in each polymer and the average number of generations of the final solution double gen = 0; double gentot = 0; //initialize variables to account for the number of each type of monomer int addnum = 0; int branchnum = 0; int chains = 0; int ochains =0; double addprob = 0; double branchprob1 = 0; double branchprob2 = 0; double alpha = 0; //initialize the variable for labelling uniqueness in original chains int namenumber = -1; //counters to keep track of the iterator positions in the deques int nucounter; int elecounter; //counter for number of iterations, debuggins int iter = 0; //obtains user input for various values needed input(chains, addnum, branchnum, addprob, branchprob1, branchprob2, alpha); //initialize the queue to hold pointers to the polymer chain ends vector<monomer*> nucleophiles; //initialize the queue to hold pointer to the reactive monomers vector<monomer*> electrophiles; //initialize the vector to hold the finished polymers vector<monomer*> polymers; //initialize [chains] number of original polymer chains and push onto nucleophiles initializechains(nucleophiles, chains, namenumber); //initialize the variable for labelling uniqueness in monomers namenumber = 1; //initialize [branchnum] number of branching monomers and push onto electrophiles initializebranchmons(electrophiles, branchnum, namenumber); //initialize [addnum] number of additive monomers and push onto electrophiles initializeaddmons(electrophiles, addnum, namenumber); //loop to build the polymers while(nucleophiles.size()!=0)// this will not be needed when the kinetics are being used { //reinitialize counters nucounter = 0; elecounter = 0; if(!electrophiles.empty())//if the elecrophiles queue is not empty there are still more monomers to react { determine_electrophile(electrophiles, elecounter, addprob, branchprob1, branchprob2, alpha); determine_nucleophile(nucleophiles, nucounter, alpha, iter); addmonomer(nucleophiles, electrophiles, nucounter, elecounter, addprob, branchprob1, branchprob2, alpha, iter); } else//if the electrophiles queue is empty we add more monomers to react { initializeaddmons(electrophiles, addnum, namenumber); initializebranchmons(electrophiles, branchnum, namenumber); } iter = iter+1; } cout<< endl<<"Polymer is done building." << endl<<endl; } void initializechains(vector<monomer*>& nucs, int& chainum, int& namenum) { if(chainum > 0) { for(int i=0; i< chainum; i++) { //pointers for the initialization of the correct monomer monomer* pointforward = NULL; //creating and initializing the monomer monomer* monomeri = new monomer(pointforward, namenum); monomeri->namenumber = namenum; //inserting the monomer onto its vector nucs.insert(nucs.begin(), monomeri); //nucs.push_back(monomeri); //nucs.push_back(monomer(pointforward, namenum)); //deleting pointers delete pointforward; monomeri = NULL; //resetting namenumber namenum = namenum - 1; } } else { cout << "there are no original chains to initialize." <<endl; } } void initializeaddmons(vector<monomer*>& elecs, int& adds, int& namenum) { if(adds > 0) { for(int i =0; i<adds; i++) { //pointers for the initialization of the correct monomer monomer* pointforward = NULL; monomer* pointbackward = NULL; //creating and initializing the monomer monomer* addmonomeri = new monomer(pointforward, pointbackward);//** addmonomeri->namenumber = namenum; //inserting the monomer onto its vector elecs.insert(elecs.begin(), addmonomeri); //elecs.push_back(addmonomeri); //deleting pointers delete pointforward; delete pointbackward; addmonomeri = NULL; //resetting namenumber namenum = namenum + 1; } } else { //cout << "there are no additive monomers to initialize." <<endl; } } void initializebranchmons(vector<monomer*>& elecs, int& branchers, int& namenum) { if(branchers > 0) { for(int i = 0; i<branchers; i++) { //pointers for the initialization of the correct monomer monomer* pointforward = NULL; monomer* pointbackward = NULL; monomer* pointbranch = NULL; //creating and initializing the monomer monomer* branchmoni = new monomer(pointforward, pointbackward, pointbranch); branchmoni->namenumber = namenum; //inserting the monomer onto its vector elecs.insert(elecs.begin(), branchmoni); //elecs.push_back(branchmoni); //deleting pointers delete pointforward; delete pointbackward; delete pointbranch; branchmoni = NULL; //resetting namenumber namenum = namenum + 1; } } else { //cout << "there are no branching monomers to initialize." <<endl; } } void addmonomer(vector<monomer*>& nucs, vector<monomer*>& elecs, int& nucount, int& elecount, double addrate_4, double branchrate1_4, double branchrate2_4, double alpha_6, int iter3) { //checks //int elesizecheck = elecs.size(); //int nucsizecheck = nucs.size(); //declare the iterators vector<monomer*>::iterator nuchooser = nucs.begin(); vector<monomer*>::iterator elechooser = elecs.begin(); //set the iterators for(int nucount2 = 0; nucount2 != nucount; ++nucount2) { ++nuchooser; } for(int elecount2 = 0; elecount2 != elecount; ++elecount2) { ++elechooser; } //see if the nucleophile and electrophile are in the same polymer bool loopy = 0; looper(nucs[nucount], loopy, elecs[elecount]->namenumber); if(elecs.size()==1 && nucs.size()==1 && (elecs[elecount]->namenumber == nucs[nucount]->namenumber || loopy ==1)) { nucs.erase(nuchooser); } else { //protection against a monomer reacting with itself if(nucs.size()==1 && elecs.size()>1 && (elecs[elecount]->namenumber == nucs[nucount]->namenumber || loopy ==1)) { while(elecs[elecount]->namenumber == nucs[nucount]->namenumber) { determine_electrophile(elecs, elecount, addrate_4, branchrate1_4, branchrate2_4, alpha_6); } //reset the electrophile iterator elechooser = elecs.begin(); for(int elecount2 = 0; elecount2 != elecount; ++elecount2) { ++elechooser; } } else if(elecs.size()==1 && nucs.size()>1 && (elecs[elecount]->namenumber == nucs[nucount]->namenumber || loopy ==1)) { while(elecs[elecount]->namenumber == nucs[nucount]->namenumber) { determine_nucleophile(nucs, nucount, alpha_6, iter3); } //reset the nucleophile iterator nuchooser = nucs.begin(); for(int nucount2 = 0; nucount2 != nucount; ++nucount2) { ++nuchooser; } } //additive monomer reaction if(elecs[elecount]->tag == 2) { //reaction nucs[nucount]->next = &*(elecs[elecount]); elecs[elecount]->previous = &*(nucs[nucount]); //reset the molecular weight, number of nodes, number of original chains elecs[elecount]->molweight = elecs[elecount]->molweight + nucs[nucount]->molweight; elecs[elecount]->nodes = elecs[elecount]->nodes + nucs[nucount]->nodes; elecs[elecount]->originalchains = elecs[elecount]->originalchains + nucs[nucount]->originalchains; //vector shuffling nuchooser = nucs.erase(nuchooser); nuchooser = nucs.insert(nuchooser, elecs[elecount]); elechooser = elecs.erase(elechooser); } //branching monomer reaction else if(elecs[elecount]->tag == 3) { //fast site if(elecs[elecount]->nextbranchtag == 2) { bool loopy2 = 0; looper(nucs[nucount], loopy2, elecs[elecount]->namenumber); if(loopy2==0) { //set the monomers fast site as reacted elecs[elecount]->branchfull = 1; //reaction nucs[nucount]->next = &*(elecs[elecount]); elecs[elecount]->branch = &*(nucs[nucount]); //reset the molecular weight, number of nodes, number of original chains elecs[elecount]->molweight = elecs[elecount]->molweight + nucs[nucount]->molweight; elecs[elecount]->nodes = elecs[elecount]->nodes + nucs[nucount]->nodes; elecs[elecount]->originalchains = elecs[elecount]->originalchains + nucs[nucount]->originalchains; //vector shuffling nuchooser = nucs.erase(nuchooser); //if electrophile has no electrophilic sites left if(elecs[elecount]->nextfull) elechooser = elecs.erase(elechooser); } } //slow site else if(elecs[elecount]->nextbranchtag == 1) { //set the monomers slowsite as reacted elecs[elecount]->nextfull = 1; //reaction elecs[elecount]->previous = &*(nucs[nucount]); nucs[nucount]->next = &*(elecs[elecount]); //reset the molecular weight, number of nodes, number of original chains elecs[elecount]->molweight = elecs[elecount]->molweight + nucs[nucount]->molweight; elecs[elecount]->nodes = elecs[elecount]->nodes + nucs[nucount]->nodes; elecs[elecount]->originalchains = elecs[elecount]->originalchains + nucs[nucount]->originalchains; //vector shuffling nuchooser = nucs.erase(nuchooser); nuchooser = nucs.insert(nuchooser, elecs[elecount]); //electrophile has no electrophilic sites left if(elecs[elecount]->branchfull) elechooser = elecs.erase(elechooser); } } } }Comment
-
so i had to cut out a lot of the code to make it less than 10000 characters long, but i included the parts where I am newing stuff and putting it onto the vectors and the parts where I am shuffling elements(pointe rs) around in the vectors.
when I think about it, the reason I used vectors of pointers is because i couldn't find out how to put my newed objects onto a vector of class objects....Comment
-
Right I begin to see your problems, my "Colour" example is clear not complex enough to be comapred to what you are trying to do.
I have some comments and some questions:
I do not know the structure of you class monomer however I infer from how you have used it that contains some (at least 3?) pointers to other instances of itself and that you have a constructor that accepts setup values for these pointers a bit like
On this basis I have the following questionsCode:class monomer { public: monomer *pointforward; monomer *pointbackward; monomer *pointbranch; // other members here monomer(monomer *pforward=NULL, monomer *pbackward=NULL, monomer *pbranch=NULL) { pointforward = pforward; pointbackward = pbackward; pointbranch = pbranch; // Initialise other members } }- You set up 3 monomer * vectors. Can a given instance of the monomer class appear in more than 1 of these vectors?
- Each monomer class contains pointers to other instances of the monomer class. Is it possible for 2 separate instances on the monomer class to end up with there internal pointers pointing to the same 3rd instance of the monomer class?
- Is it possible for an instance of a monomer class to end up in a vector and being pointed to by another instance of the monomer class.
If your answer to question 1 is YES then you definately need to be using vectors of pointers, however if it is NO then you may be able to use vectors of classes (which would probably be better as the vector then deals with the destruction of the instance for you) especially if your answer to question 3 is also NO.
Now lets examine a small fragment of your posted code
There are at least 2 other similar examples of this in your code.Code:void initializechains(vector<monomer*>& nucs, int& chainum, int& namenum) { if(chainum > 0) { for(int i=0; i< chainum; i++) { //pointers for the initialization of the correct monomer monomer* pointforward = NULL; // Some code missing here ??? //creating and initializing the monomer monomer* monomeri = new monomer(pointforward, namenum); monomeri->namenumber = namenum; //inserting the monomer onto its vector nucs.insert(nucs.begin(), monomeri); //nucs.push_back(monomeri); //nucs.push_back(monomer(pointforward, namenum)); //deleting pointers delete pointforward; monomeri = NULL; //resetting namenumber namenum = namenum - 1; } } else { cout << "there are no original chains to initialize." <<endl; } }
I do not believe that this piece of code can possibly work in the way you intend it to. First assuming that there is no code missing at the indicated point then with reference to the variable pointforward the code
- Sets it's value to NULL:
monomer* pointforward = NULL; - Uses it in the constrcution of another monomer class
monomer* monomeri = new monomer(pointfo rward, namenum); - And finally deletes it:
delete pointforward;
The the code is as it is posted then in step C it is deleting a NULL pointer. This is bound not to work.
However assuming that there is some code missing, this becomes
- Sets it's value to NULL:
monomer* pointforward = NULL; - Construct a monomer class and assign pointforward to point to it:
pointforward = new monomer(); // Or something similar - Uses it in the constrcution of another monomer class
monomer* monomeri = new monomer(pointfo rward, namenum); - And finally deletes it:
delete pointforward;
This is porbably still an error because you pass the value of pointforward into the constructor for monomeri. I assume that monomeri makes us of this value possibly by storing it in which case at step C when you delete pointforward monomeri is left referencing an object that no longer exists.
If you have a vector of objects rather than pointer to objects then you don't need to new objects, the allocator of the vector class will handle that for you see these 2 examplesOriginally posted by rokuinghwhen I think about it, the reason I used vectors of pointers is because i couldn't find out how to put my newed objects onto a vector of class objects....
In the second example the nucs vector news the new monomer instance I then provide it with initialisation data. However for that to work properly you may well have to provide a conpy constructor and overload the assigment operator...Code:// Vector of pointers vector<monomer*> Nucsp; monomer* pointforward = new monomer(); monomer* monomeri = new monomer(pointforward, namenum); //inserting the monomer onto its vector nucsp.insert(nucsp.begin(), monomeri); // Compare with // Vector of Objects vector<monomer> Nucs; //inserting the monomer onto its vector nucs.insert(nucs.begin(), monomer(pointforward, namenum));
I hope this provides some insights and leads you onto the next set of questions.Code:class monomer { public: monomer(monomer ©) { this->data = copy.data; // For allocated data remember to allocate and copy this->allocatedData = new char[10]; memcpy(this->allocatedData, copy.allocatedData, 10); } monomer operator=(monomer ©) { // Simialr to copy constructor but remember to deallocate memory //before reallocating it so as to avoid memory leaks this->data = copy.data; // For allocated data remember to allocate and copy if ( this->allocatedData != NULL ) { delete[] this->allocatedData; } this->allocatedData = new char[10]; memcpy(this->allocatedData, copy.allocatedData, 10); } }Comment
-
exactly, except that there are three different constructors, one takes one pointer to initialize a monomer with one pointer, one takes two pointers to initialize a monomer with two pointers, and one takes three pointers to initialize a monomer with three pointers. if you look in the posted code, there are four different constructors being used, each of the three mentioned above and the default.I do not know the structure of you class monomer however I infer from how you have used it that contains some (at least 3?) pointers to other instances of itself and that you have a constructor that accepts setup values for these pointers a bit like
Code:class monomer { public: monomer *pointforward; monomer *pointbackward; monomer *pointbranch; // other members here monomer(monomer *pforward=NULL, monomer *pbackward=NULL, monomer *pbranch=NULL) { pointforward = pforward; pointbackward = pbackward; pointbranch = pbranch; // Initialise other members } }
yesOn this basis I have the following questions- You set up 3 monomer * vectors. Can a given instance of the monomer class appear in more than 1 of these vectors?
- Each monomer class contains pointers to other instances of the monomer class. Is it possible for 2 separate instances on the monomer class to end up with there internal pointers pointing to the same 3rd instance of the monomer class?
- Is it possible for an instance of a monomer class to end up in a vector and being pointed to by another instance of the monomer class.
yes
yes
the third vector is only used at the very end of the program to store the final products. the first two vectors are used throughout, and these have multiple occurances of the same monomer being in both. As there are three different types of monomers with 1, 2, or 3 pointers, the end product is a vector full of pointers to non-complete binary trees of monomers. with only the positions of the most "senior" monomers of each tree (root nodes) being stored in the vectors as pointers. so the monomers with only one pointer are the leaves, the monomers with two pointers are the sections between branch-points, and the monomers with three pointers are the branch-points themselves.
i guess the pointforward pointer doesn't need to be deleted, i was just covering my ass. I only initialize it to pass into the constructor so that it knows which constructor to use, (i.e. which type of monomer to make). This is necessary, i think, because I need monomers of different types. Would it be better to used multiple classes, i.e. class monomer1, class monomer2, class monomer3, rather than have three different constructors?? or a series of derived classes.- Sets it's value to NULL:
monomer* pointforward = NULL; - Uses it in the constrcution of another monomer class
monomer* monomeri = new monomer(pointfo rward, namenum); - And finally deletes it:
delete pointforward;
The the code is as it is posted then in step C it is deleting a NULL pointer. This is bound not to work.
the program runs most of the time. but when i input big numbers (corresponding to the number of each type of monomer to be initialized) it crashes.
i think there is a memory leak, either upon initialization of the monomers, or somewhere in the vector shuffling.Comment
-
It is unlikely that "memory leaks" are causing the crash unless your system has fairly limited memory, however I assume this code is running on a PC. A memory leak is basically defined as losing track of a piece allocated memory by removing the last reference (pointer) to it so that it can not be freed.the program runs most of the time. but when i input big numbers (corresponding to the number of each type of monomer to be initialized) it crashes.
i think there is a memory leak, either upon initialization of the monomers, or somewhere in the vector shuffling.
On a lot of modern systems (WIN32) even if you do this the OS remembers that the memory is allocated and automatically deallocates it when the program closes.
The only way a "memory leak" could cause a crash is if all RAM was used up causing a new or malloc to fail and the return of these functions is not checked.
new and malloc can fail for other reasons too so when you new or malloc something you should check what is returned like so
The other thing that could be going on is deleting something before it is finished with. If you have new'd something stored the pointer to it and then deleted it the stored pointer will be pointing at nothing and trying to use it could easily cause a crash.Code:monomer *monomeri = new monomer(pointforward, namenum); if (monomeri != NULL) { // Pointer good continue processing } else { // Pointer bad memory allocation failure handle error }
My advice is to add an allocation check to everywhere that you new something even if all you do in the error handling is print a message and exit and to examine all the places you delete an object to make sure that it really is only happening when the objects are no longer in use.Comment
Comment