Strange error regarding STL vector of pointers - c++

I've a small code snippet which produces an error on running. The following code stores data of mystruct and creates a vector of pointers which store the addresses of the corresponding data.
struct mystruct{
std::vector < int > someinfo;
int somenumbers;
double *somepointer;
double someparm;
void Print(){....}
};
void DoSomething(mystruct &_somestruct, std::vector< mystruct > &_somevec,
std::vector<mystruct *> &_ptr){
_somevec.push_back(_somestruct);
_ptr.push_back(&(_somevec.back()));
}
void ReadStruct(){
std::vector<mystruct > _vec;
std::vector<mystruct *> _ptr;
for(int i=0;i<100;i++){
mystruct _struct;
_struct.somenumbers = 3;
_struct.someinfo.push_back(0);
_struct.someinfo.push_back(1);
_struct.someinfo.push_back(2);
DoSomething(_struct, _vec, _ptr);
}
_vec[0].Print(); //Prints correctly
_ptr[0]->Print();//Prints garbage info
}
If I first create the vector and then create the vector of pointers then the code works perfectly i.e.
void DoSomething(mystruct &_somestruct, std::vector< mystruct > &_somevec){
_somevec.push_back(_somestruct);
//_ptr.push_back(&(_somevec.back()));
}
void DoSomething1(std::vector< mystruct > &_somevec, std::vector<mystruct *> &_ptr){
for(int i=0;i<_somevec.size();i++)
_ptr.push_back(&(_somevec[i]));
}
I do not know what mistake I am doing. Your help/inputs is greatly appreciated!!

This does not look very safe to me.
In _ptr.push_back(&(_somevec.back())); you are taking the address of an element in _somevec. But when _somevec is changed by e.g. a push_back the address will be invalid!
For example this will not work:
std::vector<int> v;
v.push_back(17);
int* p = &v.back(); // pointer is valid
for(int i=0; i<10; i++) v.push_back(0);
*p = 42; // ERROR: p is no longer valid!
You can make this a bit better by using reserve prior to using push_back.
std::vector<int> v;
v.reserve(100); // v will now have enough room to not reallocate memory
v.push_back(17);
int* p = &v.back(); // pointer is valid
for(int i=0; i<10; i++) v.push_back(0);
*p = 42; // (probably) OK: p is still valid
But I would not recommend to do this.

It looks as if you are inserting elements into one vector and reference them with pointers from another vector. However, there doesn't seem to be any precaution against the vector of objects running out of capacity and relocating the objects, invalidating all the pointer.
The easiest approach to verify this hypothesis is to see if the capacity() of the vector of objects ever changes. The easiest fix is probably to use a std::deque<mystruct> as a std::deque<T> doesn't relocate its objects when adding/removing objects at either end.

Related

Creating and storing objects in a container without using new?

Say I have the class
class A{
int value;
public:
A(int val) : value(val) {};
}
I store pointers of instances in a collection such as vector using for loop
std::vector<A*> myCollection;
for (int i = 0; i < 10; ++i){
myCollection.push_back(&A(i));
}
Now the for loop will construct and destruct an object at the same memory location resulting in a vector with 10 pointers pointing to the same address and dereferencing them will give A->value = 9.
Is there any way around this without dynamic allocation? And yes I have to use collection of pointers and not references.
If the objects need to be on the stack, but you also want a vector of pointers because of some API requirement, etc., Just create an array of the objects, then store the pointers. Be very mindful of the lifetime issues.
size_t const sz = 3;
A arr[sz] {1, 2, 3};
std::vector<A*> v;
v.reserve(sz);
for (auto& a : arr) v.push_back(&a);
someFunc(v);
The problem with your current program is that A(i) is a prvalue and hence its address using the & operator cannot be taken. This means that the following expression is invalid in your code:
//---------------------vvvvv----->invalid because A(i) is a prvalue
myCollection.push_back(&A(i));
You could instead use a std::vector<A> in addtion to std::vector<A*> as shown below:
std::vector<A> myVector;
myVector.reserve(10);
//-------^^^^^^^---------------->to avoid reallocations when capacity is not enough
for (int i = 0; i < 10; ++i){
myVector.emplace_back(i);
//-----------^^^^^^^^^^^^------->use emplace_back to forward the argument i
}
std::vector<A*> myPtrVector;
myPtrVector.reserve(10);
for(auto&elem: myVector)
{
myPtrVector.push_back(&elem);
}

How to convert an array of string pointers into a vector of smart pointers of type string?

I have a code like this:
std::string* string_ptr[] = { new std::string("x"), new std::string("y"), new std::string("z") };
I need to get a vector like this:
std::vector<std::unique_ptr<string>> vec;
I also need to clear memory in the original string_ptr array and in the new vector.
How to do it better?
If u want to transfer the ownership to a vector, you can do as follows (after this u won't have to free any memory. the vector will manage that)
int main() {
std::string* string_ptr[] = { new std::string("x"), new std::string("y"), new std::string("z") }; // step 1
size_t sze = size(string_ptr);
std::vector<std::unique_ptr<std::string>> vec(sze); // step 2
for(size_t i{}; i < sze; ++i){
vec[i].reset( string_ptr[i]);
string_ptr[i] = nullptr;//transfer the elments ownership
}
}
If you want to copy them only(you will have to manage the memory held by the raw pointers)
int main() {
std::string* string_ptr[] = { new std::string("x"), new std::string("y"), new std::string("z") }; // step 1
size_t sze = size(string_ptr);
std::vector<std::unique_ptr<std::string>> vec(sze); // step 2
for(size_t i{}; i < sze; ++i){
;
vec[i].reset(new std::string{*string_ptr[i]});
}
vec.erase(vec.end()-1);
}
See Why can I not push_back a unique_ptr into a vector?
You could write
std::vector<std::unique_ptr<std::string>> vec{&string_ptr[0], &string_ptr[3]};
This transfers the pointers into std::unique_ptr<std::string> objects inside the vector. But keep in mind, you don't need to free the strings in string_ptr since they are now held by the unique pointers inside the vector.
Some further advice: Don't allocate strings in an array and transfer them later to the vector. This isn't exception safe. There will be memory leaks if an exception occurs until the end of the second step. If possible, don't use pointers at all:
std::vector<std::string> vec{ "x", "y", "z" };
or put the string pointers right away into the container:
std::vector<std::unique_ptr<std::string>> vec;
vec.emplace_back(std::make_unique<std::string>("x"));
// ...

How do I push vectors by reference?

This code below doesn't work because I push_back the vectors a and b to the vector vector and then alter the vectors a and b. I want to alter the vectors a and b so that the vector vector suffers the same modifications. How do I do this?
#include <iostream>
#include <vector>
int main()
{
std::vector<std::vector<int>>vector;
std::vector<int>a;
std::vector<int>b;
vector.push_back(a);
vector.push_back(b);
for (int i = 1; i <= 10; i++)
a.push_back(i);
for (int i = 11; i <= 20; i++)
b.push_back(i);
std::cout << vector[1][0];
std::cin.get();
}
You can use std::reference_wrapper (since C++11).
std::reference_wrapper is a class template that wraps a reference in a copyable, assignable object. It is frequently used as a mechanism to store references inside standard containers (like std::vector) which cannot normally hold references.
e.g.
std::vector<std::reference_wrapper<std::vector<int>>> v;
std::vector<int> a;
std::vector<int> b;
v.push_back(a);
v.push_back(b);
for (int i = 1; i <= 10; i++)
a.push_back(i);
for (int i = 11; i <= 20; i++)
b.push_back(i);
std::cout << v[1].get()[0]; //11
LIVE
Note that if the vector has longer timelife than a and b, then when a and b get destroyed the references stored in the vector become dangled.
Create v (vector is not a good name since it shares with the library and makes the code confusing) to be a vector of vector pointers (since a vector of references is not possible):
std::vector<std::vector<int> *> v; //declare as vec of vec pointers
...
v.push_back(&a); //push_back addresses of a and b
v.push_back(&b);
...
std::cout << v.at(1)->at(0) //dereference and call at on the inner vec
Note that this can be dangerous if a or b go out of scope before v, as that will leave you with dangling pointers, a mess of undefined behavior and a murder time-consuming bugs.
The basic issue is that push_back copies its parameter to the end of the vector. To modify the object in the vector, you need to get a reference to it. One approach:
std::vector< std::vector<int> > my_vector;
my_vector.reserve(2); // Going over the allocation invalidates references
my_vector.push_back( std::vector<int>() );
std::vector<int> & a = my_vector.back();
my_vector.push_back( std::vector<int>() );
std::vector<int> & b = my_vector.back();
(I changed the name of the variable because using "vector" as a variable name tends to lead to confusion.)
If you can use C++17, there is a way to reduce the lines of code using emplace_back.
If you know the number of vectors ahead of time you can do it like this:
std::vector<std::vector<int>> v(2);
std::vector<int> &a = v[0];
std::vector<int> &b = v[1];
...

newbie question about pointer to stl

I have written this function
vector<long int>* randIntSequence(long int n) {
vector<long int> *buffer = new vector<long int>(n, 0);
for(long int i = 0; i < n; i++)
buffer->at(i);
long int j; MTRand myrand;
for(long int i = buffer->size() - 1; i >= 1; i--) {
j = myrand.randInt(i);
swap(buffer[i], buffer[j]);
}
return buffer;
}
but when I call it from main, myvec = randIntSequence(10), I see the myvector always empty. Shall I modify the return value?
The swap call is indexing the *buffer pointer as if it were an array and is swapping around pointers. You mean to swap around the items of the vector. Try this modification:
swap((*buffer)[i], (*buffer)[j]);
Secondary to that, your at calls don't set the values as you expect. You are pulling out the items in the vector but not setting them to anything. Try one of these statements:
buffer->at(i) = i;
(*buffer)[i] = i;
You never assign to any of the elements in the vector pointed to by buffer:
for (long int i = 0; i < n; i++)
buffer->at(i); // do you mean to assign something here?
You end up with the vector containing n zeroes.
Your question has already been answered, so I'll make this CW, but this is how your code should look.
std::vector<long int> randIntSequence(long int n)
{
std::vector<long int> buffer(n);
for(int i=0; i<n; ++i)
buffer[i] = i;
std::random_shuffle(buffer.begin(), buffer.end());
return buffer;
}
There is absolutely no reason you should be using a pointer here. And unless you have some more advanced method of random shuffling, you should be using std::random_shuffle. You might also consider using boost::counting_iterator to initialize the vector:
std::vector<long int> buffer(
boost::counting_iterator<long int>(0),
boost::counting_iterator<long int>(n));
Though that may be overkill.
Since the question is about STL, and all you want is a vector with random entries then:
std::vector<long int> v(10);
generate( v.begin(), v.end(), std::rand ); // range is [0,RAND_MAX]
// or if you provide long int MTRand::operator()()
generate( v.begin(), v.end(), MTRand() );
But if you want to fix your function then
n should be size_t not long int
First loop is no-op
As John is saying, buffer is a pointer, so buffer[0] is your vector, and buffer[i] for i!=0 is garbage. It seems you have been very lucky to get a zero-sized vector back instead of a corrupt one!
Is your intention to do random shuffle? If yes, you are shuffling around zeros. If you just want to generate random entries then why don't you just loop the vector (from 0 to buffer->size(), not the other way around!!) and assign your random number?
C++ is not garbage collected, and you probably don't want smart pointers for such simple stuff, so you'll be sure to end up with leaks. If the reason is in generating a heap vector and returning by pointer is avoiding a copy for performance's sake, then my advise is don't do it! The following is the (almost) perfect alternative, both for clarity and for performance:
vector<T> randIntSequence( size_t n ) {
vector<T> buffer(n);
// bla-bla
return buffer;
}
If you think there is excess copying around in here, read this and trust your compiler.

return underlying array from vector

Will the array be deallocated and if so, what is a workaround?
double * GetArrayFromVector( std::map<std::string, double> m, char ** names, int count )
{
if(!names) return 0;
std::vector<double> vec(m.size());
for (int i=0; i<count; ++i)
{
if(!names[i]) return 0;
std::map<std::string, double>::iterator iter=m.find(name[i]);
if(iter!=m.end())
vec.push_back(iter->second);
else
return 0;
}
return &vec[0];
}
Thanks a lot
Divide your function on two.
Make your functions make just one action:
1. fill vector from map.
2. create array from vector.
Don't forget to pass map by const reference.
Main note: caller of the GetArrayFromVector is responsible for memory deallocation.
void FillVector( const std::map<std::string, double>& m,
std::vector< double >& v,
char ** names,
int count )
{
.......
}
double* createArray( const std::vector< double >& v )
{
double* result = new double [v.size()];
memcpy( result, &v.front(), v.size() * sizeof( double ) );
return result;
}
// and finally your function
double* GetArrayFromVector( const std::map<std::string, double>& m,
char ** names,
int count )
{
std::vector< double > v;
FillVector( m, v, names, count );
return CreateArray( v );
}
Yes -- it's deallocated as soon as your return from the function, because vec is declared on the stack. The std::vector destructor takes care of freeing the memory. Since you're returning the address of a deallocated array, you're going to start messing around with deallocated memory, which is a big no-no. At best, you'll crash immediately. At worst, you'll silently succeed with a big gaping security hole.
There are two ways to fix this: (1) return the entire vector by-value, which makes a copy of the entire vector, or (2) return the vector via a reference parameter.
Solution 1:
std::vector<double> GetArrayFromVector(...)
{
...
return vec; // make copy of entire vec, probably not a good idea
}
Solution 2:
void GetArrayFromVector(..., std::vector<double> & vec)
{
// compute result, store it in vec
}
Yes the array will be deallocated.
Change the function to:
double * GetArrayFromVector( std::map<std::string, double> m, vector<double> &vec, char ** names, int count )
{
vec.clear();
vec.reserve(m.size());
for (int i=0; i<count; ++i)
{
if(!names[i]) return 0;
std::map<std::string, double>::iterator iter=m.find(name[i]);
if(iter!=m.end())
vec.push_back(iter->second);
else
return 0;
}
return &vec[0];
}
Or else use boost::shared_array (also, look at boost::scoped_array)
boost::shared_array<double> GetArrayFromVector( std::map<std::string, double> m, char ** names, int count )
{
boost::shared_array<double> vec(new double[m.size()]);
for (int i=0; i<count; ++i)
{
if(!names[i]) return boost::shared_array<double>();
std::map<std::string, double>::iterator iter=m.find(name[i]);
if(iter!=m.end())
vec[i] = iter->second;
else
return boost::shared_array<double>();
}
return vec;
}
vec is a local variable. Its scope is limited to the GetArrayFromVector() function only. Never return the address of a local variable. Either return the array by value:
std::vector<double> GetArrayFromVector( std::map<std::string, double> m,
char ** names, int count )
or, pass a reference to the vector as an output parameter:
void GetArrayFromVector( std::map<std::string, double> m,
char ** names, int count,
std::vector<double>& vec)
or, pass an output iterator:
void GetArrayFromVector( std::map<std::string, double> m,
char ** names, int count,
std::vector<double>::iterator vecIter)
The last two will require some careful implementation of the function definition and calling though.
Additionally, if you are game for a bit more adventure try this:
// you'd need to change the value to use when an element is not
// found in the map to something that suits your needs
double pred(std::map<char*, double> haystick, char* const needle) {
std::map<char*, double>::iterator i = haystick.find(needle);
return i != haystick.end() ? i->second : 0;
}
int main(int argc, char* argv[])
{
std::map<char *, double> m;
std::vector<char *> names;
std::vector<double> dv;
m[ "Sasha" ] = 729.0;
m[ "josh" ] = 8154.0;
names.push_back("Sasha");
names.push_back("JonSkeet");
names.push_back("josh");
// transform is part of STL's <algorithm> header
// it takes a container (actually a range -- [begin(), end())
// note it is a half-open range -----------^
// as is customary for all STL algorithms, applies the function
// or functor specified as the last parameter to each element of
// the sequence and writes the result back to another container
// specified via the output iterator -- the third argument
//
// since I have not reserved enough elements for the vector dv
// i cannot blindly use it -- i need a back_inserter to coax
// transform to push_back() instead of do an insert operation
// of course, for vectors, this is costly since reallocations
// may happen, but let's leave the performance aside for a while!
//
// ok, so what about the last parameter, you ask? it has to be an
// unary_operation. well, mostly so. but what is it that we want?
// we want to take an iterator from the original char* (string)
// array and see if there's an entry in the map. if there is one
// we retrieve the associated double value and put it in dv; else,
// we set a default value of 0 -- change it to whatever pleases you
// maybe a std::numeric_limit<double> if it works for you.
//
// you can create a functor inheriting std::unary_function and pass
// it on. that's the easy way out. but what if you already have a
// comparator, a C-style find() function? will it work? yes, it will.
// but we have to wrap it using the function adaptor std::ptr_fun
// to make the compiler happy (after all it wants a unary_function, right?)
//
// this simple scheme of things works very well, save for a last little
// glitch. the comparator actually takes two parameters -- a what to search
// and a where to search. and guess what -- the where to search is always
// fixed. so that gives us a good oppertunity to fix the first parameter to
// our map<char*, double> which is exactly what std::bind1st() does.
// surprisingly, now that you've fixed one function, you no longer have a
// binary function (one taking two arguments) but an unary one -- which is
// just what you'd pass to transform. voila!
std::transform(names.begin(), names.end(), std::back_inserter(dv),
std::bind1st(std::ptr_fun(pred), m));
std::copy(dv.begin(), dv.end(),
std::ostream_iterator<double>(std::cout, "\n"));
return 0;
}
Some interesting links:
transform [actually, comes in two flavors]
bind1st or binder1st [there's a binder2nd too!]
back_inserter
ptr_fun [check out mem_fun also]
unary_function [and there's binary_function]
Also check out Boost. They have done some magic with bind()!
You can pass it by reference or new/delete it, but as posted your vector will be destructed after the function returns.
Yes, the vector (and the data store it holds) will be deallocated when the function ends.
Why are you creating a vector? If you want an array, just create & fill one of those..
double * GetArrayFromVector( std::map<std::string, double> m, char * names[], int count )
{
if(!names) return 0;
double* vec = new double[m.size()];
int j = 0;
for (int i=0; i<count; ++i)
{
if(!names[i]) return 0;
std::map<std::string, double>::iterator iter=m.find(name[i]);
if(iter!=m.end())
vec[j++] =iter->second;
else
return 0;
}
return vec;
}
Yes the vector will be deallocated when the function exits (and the 'vec' variable goes out of scope). The pointer you return will therefore be invalid.
An alternative is to allocate the array on the heap (using the 'new' operator) and return that pointer instead, but it will be the caller's responsibility to 'delete' the pointer, which is usually frown upon.
A better alternative is to return a shared_ptr to your array.
Since you know count up front, there's no benefit to using an stl vector. You could simply do this:
double* GetArrayFromVector(std::map<char*, double> m, char** names, int count)
{
double* result = new double[count];
for (int i = 0; i < count; ++i)
{
if(!names[i])
{
delete[] result;
return 0;
}
map<std::string, double>::iterator iter = m.find(name[i]);
if(iter != m.end())
{
result[i] = iter->second;
}
else
{
delete[] result;
return 0;
}
}
return result;
}
Note that you are passing ownership of the allocated array to the caller. Personally, I'd try to write the code in a way that observes the RAII principle; either pass in a vector to be populated, or use a managed/shared pointer, etc. (both of these options have been suggested in other answers).
There is a concept call move constructors that would allow you to transfer the ownership of a resource held by a (stack-based) object to a new object. I have heard that STLport has a move_source template to accomplish this
This will be coming to C++0x.
In this case, you would be returning std::vector<double> instead of double*.
Kinda surprised no one has mentioned vector::swap. Have the caller pass in a reference to a vector which will have its contents replaced by the function:
void GetArrayFromVector( std::vector<double>& output, ... )
{
std::vector<double> vec(m.size());
// construct vec here...
output.swap(vec);
}
BTW: "GetArrayFromVector" and you pass in a map?
You could use std::auto_ptr smart pointer (but passing vector reference to your function is better solution).
Example of std::auto_ptr:
std::auto_ptr< std::vector<int> > getArray(int& count){
std::auto_ptr< std::vector<int> > vec(new std::vector<int>());
vec->push_back(10);
vec->push_back(12);
vec->push_back(14);
vec->push_back(16);
count = vec->size();
return vec;
}
int main(){
int size = 0;
std::auto_ptr< std::vector<int> > autoPtrVec = getArray(size);
int* ptr = &(*autoPtrVec)[0];
std::cout << "Size: " << size << std::endl;
for(int i=0; i<size; i++){
std::cout << "[" << i << "]=" << ptr[i] << std::endl;
}
return 0;
}
C++ vectors have a data() method which returns a pointer to the underlying array.
// vector::data
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector (5);
int* p = myvector.data();
*p = 10;
++p;
*p = 20;
p[2] = 100;
std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); ++i)
std::cout << ' ' << myvector[i];
std::cout << '\n';
return 0;
}
which outputs
myvector contains: 10 20 0 100 0