Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 transform with shared_ptr to a vector and class

I am trying to apply transform to a shared_ptr and store to a shared_ptr while also using a function in a class.

I created this example:

#include <vector>
#include <iostream>
#include <memory>
#include <algorithm>

using namespace std;

class MyClass {
public:
    int factor = 0;
    MyClass(const int factor_) : factor(factor_) {}

    shared_ptr<vector<int> > mult(shared_ptr<vector<int> > numbers) {
        shared_ptr<vector<int> > result(new vector<int>() );

        transform(numbers->begin(), numbers->end(), result->begin(),
            [this](int x){ return factor * x; });

        return result;
    }
};

int main()
{
    shared_ptr<vector<int> > numbers(new vector<int>());
    shared_ptr<vector<int> > res(new vector<int>());
    MyClass times_two(2);

    numbers->push_back(1);
    numbers->push_back(2);
    numbers->push_back(3);

    res = times_two.mult(numbers);

    cout << "{";
    for (unsigned int i = 0; i < res->size(); ++i)
        cout << res->at(i) << ", ";
    cout << "}";    

    return 0;
}

As can be seen here this causes a segmentation dump. Any help on how I could resolve this so that the output yields {2, 4, 6, }?

Note that I use the lambda because I need it in my full implementation.

I tried also to replace,

transform(numbers->begin(), numbers->end(), result->begin(),
        [this](int x){ return factor * x; });

with

transform((*numbers).begin(), (*numbers).end(), (*result).begin(),
        [this](int x){ return factor * x; });
like image 310
Stereo Avatar asked Sep 11 '16 03:09

Stereo


1 Answers

    shared_ptr<vector<int> > result(new vector<int>() );

You construct a new, empty vector.

    transform(numbers->begin(), numbers->end(), result->begin(),
        [this](int x){ return factor * x; });

Since result is empty, result->begin() returns the ending iterator value. std::transform copies the input sequence, applies the transformation lambda, and writes the transformed result to the output iterator.

Since the vector is empty, there's nothing to write to. You're running past the end of the empty array, resulting in undefined behavior and memory corruption.

In this case, simply preallocate the output array, since you know what its size should be, in advance:

shared_ptr<vector<int> > result(new vector<int>(numbers->size()) );

Now, this will create the output array of the correct size, begin() will return an iterator to the beginning of the array, and std::transform() will happily scribble over the array.

If you really wish to avoid the extra overhead of value-initializing the new array, just to have it overwritten, you can use reserve() to preallocate the array's final size, then use a std::back_insert_iterator for the output iterator, instead of passing in begin().

like image 98
Sam Varshavchik Avatar answered Oct 15 '22 16:10

Sam Varshavchik