I have a loop which adds pointers to a vector;
vector<Material *> materials;
and my Material class has 4 attributes :
int id;
float *ambiance;
float *diffuse;
in my loop :
while(input_read_from_the_file !=NULL){
int id=someval1;
float x[2]={someval2,someval3};
float y[2]={someval4,someval5};
materials.push_back(new Material(id,x,y));
}
When I read my materials vector in a for loop I see that ids are different but ambiance and diffuse are same for all the elements.Thats probably because it uses the same pointer in the while loop but I couldnt find an alternative.What should be the best approach here?
Thanks
I'd try to avoid pointers as much as I can.
Let's start with your vector. Why does it need to be vector<Material*> and not vector<Material>?
Unless Material is an inherited class, you can use a vector of Material objects instead of pointers.
That way, you don't need the destructor of the class that has vector<Material*> to iterate and destroy each of them (by using shared_ptr, you can avoid this too).
Now, as mentioned in the comments, the problem is that Material uses pointers for the ambiance and diffuse members. No reason for that too.
Technically, you want it to be Vector3 or Vector4 when you're writing a renderer or material system, but lets go with float[2] instead.
C++11 (0x) has cool move semantics that you can use to avoid the creation of a temporary object (since we're going to push an object into the vector and without move semantics, a temporary object is created while doing so)
So, your code looks like:
class Material {
int id;
float ambiance[2]; // you really ought to use Vector2 instead. pointers are evil.
float diffuse[2];
Material (const int _id, const float _amb[], const float _dif[]) : id(_id) {
ambiance[0] = _amb[0]; ambiance[1] = _amb[1]; // actual copy is made
diffuse[0] = _dif[0]; diffuse[1] = _dif[1];
}
}
-----
vector<Material> materials;
while(input_read_from_the_file !=NULL){
int id = someval1;
float x[2]= {someval2,someval3};
float y[2]= {someval4,someval5};
materials.emplace_back(Material(id,x,y)); // or even materials.emplace_back(id, x, y);
}
Related
I'm trying to realize two methds append() and clear().
In appened(), I need to newPoint to the end of a list. If the list is empty, then adds newPoint as the first(and only) point in the list.
In clear(),I need to remove all the points in a list.
Can you give me some advice to realize appened and clear.
Here is a code:
//
#pragma once
const int maxListSize = 10;
class Point
{
private:
float x;
float y;
public:
Point(float x0 = 0, float y0 = 0)
{
x = x0;
y = y0;
}
};
class PointList
{
private:
//Data members
int size;
int cursor;
Point points[maxListSize];
public:
PointList();
//List Manipalution operations
void append(Point newPoint);
void clear();
~PointList();
};
*I don't need you to write everything for me, just give me some advice. I would like to realize it by myself. Thank you for helping.
Since you store your list elements by value (Point points[maxListSize]),
it is quite easy to do:
PointList() :size(0) {}
void append(Point newPoint) { points[size++] = newPoint; }
void clear() { size = 0; }
This assumes that your Point object doesn't manage any resource, which is true for this particular example. Otherwise, inserted Point objects should be destroyed in clear.
To get the semantics that you're probably expecting for appending new items, and clearing out existing items, I suggest you look at the placement new operator, and manually calling the destructor of an item in the list.
Currently your class will construct all of the items in the list when you create the list. This can be quite time consuming for complex structures. Then, instead of the constructor for your elements being called, you'll instead be calling the copy-assignment operator, as the items are already constructed.
If you store your array as
char * points[sizeof(Point)*maxListSize];
Any only initialize the items when they're actually added, you avoid the construction cost when you create the list.
Your append function takes it's argument by value. Instead, I recommend you have two append functions. One that takes const&, and the other that takes an rvalue-reference. Then, inside the append function, call the placement new operator on the address of the next location in your array.
To clear the array, simple call the destructor for each element in the array one at a time.
I saw a few examples of creating a vector of class objects and many of them uses a pointer and new keyword. However, in many cases the delete is not used to free up memory allocated by new. I would like to know if the following piece of code uses delete properly.
I have a class Marker:
class Marker{
public:
Marker(int, float, float);
int marker_id();
private:
int id;
float mx;
float my;
};
It's constructor is:
Marker::Marker(int idno, float x, float y){
//ctor
id = idno;
mx = x;
my = y;
}
I need a vector marker_vec with objects or instances of Marker class. Hence, I wrote the following piece of code:
vector <Marker> marker_vec;
Marker *m = new Marker(last_id, m_x, m_y);
marker_vec.push_back(*m);
delete m;
If I use the above code in a loop to create marker_vec[0] and marker_vec[1], I believe that the delete wouldn't delete them and will only free up the pointer m. Is there any disadvantages for the above method?
This piece of code is alright, since when you push_back, the contents referenced by the m pointer will be copied and added as the last element of the vector. You're doing good by deallocating the memory you set properly (for every new there is a corresponding delete).
vector <Marker> marker_vec;
Marker *m = new Marker(last_id, m_x, m_y);
marker_vec.push_back(*m);
delete m;
I just think it's unnecessary for you to use pointers in this case having one type of Marker class and your std::vector of type <Marker>.
I would personally improve the implementation of this code to being statically instantiated. It's simple and cleaner in this case:
vector <Marker> marker_vec;
Marker m(last_id, m_x, m_y);
marker_vec.push_back*m);
However, if you maybe had inheritance like different type of markers:
class HighlighterMarker : public Marker { };
and
class PenMarker: public Marker { };
Only then, it'd make sense for you to use dynamic memory and your vector to be declared as:
std::vector <Marker*> marker_vec. This one can store all your references to any type of derived class Marker,
I am converting some code between different systems, and I have a question regarding c++ vectors.
If I do something like this:
In header file:
struct Vertex
{
float x;
float y;
float z;
}
struct submesh
{
Vertex *meshdata;
}
std::vector<submesh> meshes;
In a routine in the c++ file:
{
Vertex *data = new Vertex[1024];
submesh g;
g.meshdata = data;
meshes.push_back(g);
delete [] data;
}
Will I be in trouble? My assumption is that the vector would hold a pointer to data that is no longer valid once I called delete on it. Do I need to write a copy constructor for Vertex so that the data is copied first?
Additional:
The question was more to do with how do I put a pointer to allocated memory into a std::vector<> and still cleanup the locally allocated data. Essentially, how do I copy the data into the vector so I can still clean up my copy.
The original code was in DirectX. I am porting it to the iPhone. The original code allocated a submesh locally in a routine using:
{
ID3DXMesh* subMesh = 0;
D3DXCreateMesh(SubGrid::NUM_TRIS, SubGrid::NUM_VERTS, D3DXMESH_MANAGED, elems, gd3dDevice, &subMesh));
//
// ... do some magical things to submesh
//
SubGrid g;
g.mesh = subMesh;
g.box = bndBox;
mSubGrids.push_back(g);
}
I am trying to duplicate how ID3DXMesh is able to be added to a vector, then lose it's scope in the routine.
As I don't have access to D3DXCreateMesh(), I figured I would simply allocate the vertices I needed, throw them into a vector, and clean up.
Sorry, I wanted to keep the nitty gritty details out of it, as the question is simply how do I allocate a chunk of data, put a pointer into a std::vector<>, then clean up the locally allocated memory. :)
I assumed a copy constructor had to be written somewhere. Just wasn't sure where or how.
A subgrid looks like this:
struct SubGrid
{
ID3DXMesh* mesh;
AABB box;
// For sorting.
bool operator<(const SubGrid& rhs)const;
const static int NUM_ROWS = 33;
const static int NUM_COLS = 33;
const static int NUM_TRIS = (NUM_ROWS-1)*(NUM_COLS-1)*2;
const static int NUM_VERTS = NUM_ROWS*NUM_COLS;
};
And the vector they get added to looks like:
std::vector<SubGrid> mSubGrids;
Don't directly dynamicly-allocate when you don't need to, and in this case you don't. Since you're filling your own submesh data rather than using ID3DXMesh, the container of that data should be RAII-compliant. If I were coding this I would remove the submesh class entirely and just use:
// vector containing list of vertices.
typedef std::vector<Vertex> SubMesh;
Your SubGrid class can then become a simple container that holds, as one of its properties, a submesh collection. I noticed you also have a class AABB for a box object. You would continue to keep that inside SubGrid. I don't have ton to work with here, so I'm making some of these up as I go along, but something like the following:
// a simple 3-value triplet of floats
struct Vertex
{
float x,y,z;
};
// a Submesh is an arbitrary collection of Vertex objects.
typedef std::vector<Vertex> SubMesh;
// I'm defining AABB to be an 8-vertex object. your definition
// is likely different, but I needed something to compile with =)
typedef Vertex AABB[8];
class SubGrid
{
public:
SubGrid() {};
// comparator for container ordering
bool operator <(const SubGrid&);
// submesh accessors
void setSubmesh(const SubMesh& mesh) { submesh = mesh;}
SubMesh& getSubmesh() { return submesh; }
const SubMesh& getSubmesh() const { return submesh; }
// box accessors
AABB& getBox() { return box; }
const AABB& getBox() const { return box;}
private:
SubMesh submesh;
AABB box;
};
// arbitrary collection of SubGrid objects
typedef std::vector<SubGrid> SubGrids;
When adding this to your global SubGrid collection g, you have several possibilities. You could just do this:
// declared globally
Subgrids g;
// in some function for adding a subgrid item
SubGrid subgrid;
AABB& box = subgrid.getBox();
SubBesh& submesh = subgrid.getSubmesh();
// ... initialize your box and submesh data ...
g.push_back(subgrid);
But you'd be copying a lot of data around. To tighten up the memory access you could always do this instead:
// push an empty SubGrid first, then set it up in-place
g.push_back(SubGrid());
Subgrid& subgrid = *(g.back());
AABB& box = subgrid.getBox();
SubMesh& submesh = subgrid.getSubmesh();
//... initialize your box and submesh data ...
This will establish a reference to the SubGrid just added to the global collection, then allow you to modify it in-place. This is but-one of a number of possible setup options. It should be noted that if you have C++11 in your toolchain (and if you're doing this on MacOS or iOS, you likely do, as Apple LLVM 4.2's clang is pretty good on C++11 compliance) this can get even more efficient with judicious usage of move-constructors and move-assignment-operators.
Most importantly, not a new or delete to be seen.
Anyway, I hope this gives you some ideas.
Your code looks fine in single threaded application. Your code only allocate data memory once and delete [] data once.
Do I need to write a copy constructor for Vertex so that the data is copied first?
Your code is clean as you shown, meshes points to only allocated data. If you meant to copy data when call meshes.push_back(g), then your code doesn't do what you meant to.
You might want to use std::vector instead:
struct submesh
{
std::vector<Vertex> meshdata;
}
vector<submesh> meshes;
void Func()
{
meshes.emplace_back(submesh());
meshes.at(0).meshdata.resize(100);
}
STL container uses RAII idiom, it manages memory deallocation for you automatically.
Yes of course, vector will have a pointer to deleted memory. What you need is either:
Create copy constructor for submesh (not Vertex).OR
Changesubmesh to have array of Vertex (not just a pointer).
Copy constructor can be done like this:
struct submesh
{
Vertex *meshdata;
unsigned meshsize;
submesh(Vertex* v = 0, unsigned s= 0) : meshdata(v), meshsize(s){}
submesh(const submesh& s)
{
if(meshdata) /*we have stored data, delete it.*/ delete(meshdata);
meshdata = new Vertex[s.meshsize];
meshsize = s.meshsize;
memcpy(meshdata, s.meshdata, sizeof(Vertex) * meshsize);
}
};
For sure it is much recommended to use unique_ptr (if you use c++11) or auto_ptr for old c++. To avoid the nightmare of memory management as much as you can.
Check How to avoid memory leaks when using a vector of pointers to dynamically allocated objects in C++?
I have a program that creates a random amount of points interspersed throughout the program. While it runs, I would also like to create an object for each point and store it in a vector. I have created a Point class with various attributes but I have no idea on how to implement the above. When looking at other questions that deal with similar, yet nonidentical problems, pointers are used, but again, I have no idea on how to implement them.
Im not quite sure what you really want to achieve, but i hope this will help you though.
To create an object dynmically use the new operator. The new operator always returns a pointer:
Point* pointObj = new Point();
If you have specified a constructor the call is very similar to normal construction on stack:
Point* pointObj = new Point(x,y);
A std::vector stores objects at runtime (dynamically in the heap), but instead of creating them by it own it simply copies them:
std::vector<Point> vec; //if this object is destructed it contents are destructed aswell
Point pointObj(x,y); //point on stack; will get destructed if it gets out of scope
vec.push_back(pointObj) //copy pointObj to a dynamic location on the heap
Well, I don't know what parameters your Point constructor takes, but your description sounds as if you want to do something like this:
std::vector<Point> MyGlobalPointList;
and inside your program you have a few of these:
MyGlobalPointList.push_back(Point(x,y,color));
Are you looking for automatic object management tied with object creation here? If so, AbstractFactory can help you here. Apart from the factory being THE mechanism for constructing objects (Points) instead of doing so everywhere yourself, it can also carry out object management e.g. managing them in a vector.
class Point {
friend class PointFactory;
Point(int _x, int _y) : x(_x), y(_y) { }
private:
~Point(); //destructor is private
int x, y;
}
class PointFactory {
public:
Point* createPoint() { //Creates random point
return createPoint(rand(), rand());
}
Point* createPoint(int x, int y) { //Creates specified point
Point* p = new Point(x, y);
points.push_back(p);
return p;
}
void deletePoint(Point *p) { //p not in use anymore
std::vector<Point*>::iterator it = std::find(objects.begin(), objects.end(), p);
if (it != objects.end()) {
objects.erase(it);
}
delete p;
}
private:
std::vector<Point*> objects;
}
int main(...) {
Point *p = pointFactory.createPoint(); //instead of new Point()
//use p
pointFactory.deletePoint(p); //p not in use anymore
return 0;
}
Hope this is what you are looking for.
Ankur Satle
Working on adjacency list --> directed weighted graph
One class looks like this, i.e. header:
class CGraph;
class CMap {
public:
//voided constructors and destructors
//functions one is:
void SetDirGraph(string commands);
private:
CGraph* m_myMap;
};
Second class:
class CNode {
public:
//voided constructor and desctructor
int m_distance, m_vert;
bool m_isKnown;
};
typedef struct edges {
int v2, weight;
} edge;
class CGraph {
public:
CGraph(int map_size);
~CGraph(void);
void AddMap(int v1, int v2, int weight);
void AddEndVert(int v2, int weight);
private:
list<edge> List;
int size;
public:
CNode* verts;
};
I'm reading vertices from a file, and that works. My problem is I am having trouble creating an adjacency list based on the code given. I'm trying to use pointers first that points to a list and it is not working correctly. I don't know how to create my pointers to the list without writing over them.
void CMap::SetDirGraph(string command) {
istringstream buffer(command)
char ch;
int num, vert1, vert2, weight; //specify vertices and weight and number of vertices
buffer>>ch; //throw away first character (not needed)
buffer>>num // size of vertices
while(!buffer.eof()) { // keep reading until end of line
buffer>>v1; // vertex start
buffer>>v2; // vertex end
buffer>>weight;
m_myMap = new CGraph(map_size); //initialize m_myMap.
m_myMap->verts->m_vert = v1; // mymap->verts->vert points to first edge
m_myMap->AddMap(v1, v2, weight); // create list?
m_myMap->AddEndVert(v2, weight); //create list? push v2 and weight on my list using my list.
}
}
I've tried several different ways and I keep confusing myself, any point in the right direction would be awesome.
EDIT:
I have more code too if needed to be produced, just publishing the main stuff.
What I mean by "not working" is that I am just writing over the previous vertex. I don't know if I should create an array using m_myMap (tried and still writes over and get a memory error as well). No compiler errors.
I don't know how to create my pointers to the list without writing over them.
Apart from your application, the answer to this question is the new operator, which I assume you are aware of, since you used it within your example code. Code like int * a = new int(42); allocates memory for an int on the heap and you are responsible for cleaning it up when it is not needed anymore. You thereby have full control over how long a variable will be available. In int x = 42; int * a = &x; on the other hand, x will automatically be cleaned up when it runs out of scope, and a will be a pointer to a memory block that has no meaningful data in it anymore. If you try to dereference it, you will encounter undefined behavior, and, if you are lucky, your program will blow up.
If you can use the C++11 standard, or a library that offers smart pointers, you should prefer those over managing the pointer yourself whenever possible. A smart pointer is an object that holds the allocated memory and frees it automatically when it is destructed. More specific information depends heavily on which sort of smart pointer you are using. The reason for using smart pointers is that doing the management yourself is tedious and error prone. If you do not delete your pointers you had allocated, your application will keep on allocating more memory until it blows up some day (depending on how often and how much memory you allocate); this is called leaking. If you call delete more than once, your program will bail out as well. Here is an example of C++11 shared_ptr in your application:
class CMap
{
private:
std::shared_ptr<CGraph> m_myMap;
// etc.
};
// in SetDirGraph
m_myMap.reset( // if the smart pointer has previously been managing
// memory, it will free it before allocating new
new CGraph(map_size) // allocate CGraph as before
);
Besides that, what hopefully answers your question, I have run into several potential problems concerning your code:
Definitely wrong:
In SetDirGraph you set m_myMap->verts->m_vert = v1. m_myMap->verts is a pointer. You have freshly created m_myMap and thus verts is not initialized, hence pointing at a random block of memory. You then try to dereference it by m_myMap->verts->m_vert = v1. This cannot work. You need to create verts first, i.e. verts = new CNode;.
typedef struct edges { /* etc */ } edge; is a C construct and there is no need for the typedef wrapper in C++. It does work and all, but it is really redundant and lots of those constructs just pollute the namespace you are working in.
Do you really need pointers in the first place? Your provided snippets do not hint at why you would need to use them. You will want to reduce usage of pointers to a minimum (or at least use smart pointers, see above)