Yeo Yeo - 3 months ago 10
C++ Question

How to construct a new vector/set of pointer from another vector/set of object?

Background



I wanted to manipulate the copy of a vector, however doing a vector copy operation on each of its element is normally expensive operation.

There are concept called shallow copy which I read somewhere is the default copy constructor behavior. However I'm not sure why it doesn't work or at least I tried to do the copy of vector object and the result looks like a deep copy.

struct Vertex{
int label;
Vertex(int label):label(label){ }
};

int main(){
vector<Vertex> vertices { Vertex(0), Vertex(1) };

// I Couldn't force this to be vector<Vertex*>
vector<Vertex> myvertices(vertices);

myvertices[1].label = 123;

std::cout << vertices[1].label << endl;
// OUTPUT: 1 (meaning object is deeply copied)

return 0;
}


Naive Solution: for pointer copy.



int main(){
vector<Vertex> vertices { Vertex(0), Vertex(1) };

vector<Vertex*> myvertices;
for (auto it = vertices.begin(); it != vertices.end(); ++it){
myvertices.push_back(&*it);
}

myvertices[1].label = 123;

std::cout << vertices[1].label << endl;
// OUTPUT: 123 (meaning object is not copied, just the pointer)

return 0;
}


Improvement



Is there any other better approach or
std::vector
API to construct a new vector containing just the pointer of each of the elements in the original vector?

Answer

One way you could transform a vector of elements to a vector of pointers that point to the elements of the original vector that is better in terms of efficiency compared to your example, due to the fact that it preallocates the buffer of the vector of pointers, and IMHO more elegant is via using std::transform as follows:

std::vector<Vertex*> myvertices(vertices.size());
std::transform(vertices.begin(), vertices.end(), myvertices.begin(), [](Vertex &v) { return &v; });

Live Demo

Or if you don't want to use a lambda for the unary operator:

std::vector<Vertex*> myvertices(vertices.size());
std::transform(vertices.begin(), vertices.end(), myvertices.begin(), std::addressof<Vertex>);

Live Demo

Caution: If you alter the original vector then you invalidate the pointers in the pointers' vector.

Comments