简体   繁体   中英

unstable memory allocation in C++11

I'm getting unstable results with my software and wanted to understand why and how I should modify my code to get consistent results. To show this, I prepared a mock sample of the software; below, I have 2 main classes, Mother and Daughter ; these are my main data structures, and I use Mother in many other data structures. Hence, it's essentially an abstract class but can not be purely abstract since some of the observables are also directly dependent on it, so I can not write (as far as I know) pure virtual functions in it. Classes are defined as follows;

#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
#include <vector>

using namespace std;

class Mother {
    private:
        double some_var_;

    public:
        Mother() {some_var_ = 0.;}

        virtual ~Mother() {}

        virtual void print() const
        {
            std::cout << "printing from mother " << some_var_ << std::endl;
        }

        virtual void setvar(double v) {some_var_ = v;}

        virtual const double var() const {return 0.;}
};

class Daughter : public Mother
{
    private:
        double new_var_;

    public:
        Daughter() {new_var_ = 0.;}

        virtual ~Daughter() {}

        void print() const
        {
            std::cout << "printing from Daughter " << new_var_ << std::endl;
        }

        void setvar(double v) {new_var_=v;}

        const double var() const {return new_var_;}
};

I interact with these data structures through a collection class defined as follows;

class collection
{
    private:
        std::vector<Daughter> daughters_;

    public:
        collection () {Reset();}

        virtual ~collection() {}

        void Reset() {daughters_.clear();}

        Daughter* GetNewDaughter()
        {
            daughters_.push_back(Daughter());
            return &daughters_.back();
        }

        const std::vector<Daughter>& daughters() {return daughters_;}
};

Given these, I defined a filter function to trim these data structures;

template <class T, typename FN>
std::vector<const T*> filter(std::vector<T> objects, FN func)
{
    std::vector<const T*> filtered;
    for (auto &obj: objects)
    {
        if (func(&obj)) filtered.push_back(&obj);
    }
    return filtered;
}

And the code body is as follows;

int main(int argc, char** argv)
{
    collection* col = new collection();
    for (unsigned int i=0; i<5; i++)
    {
        Daughter* current = col->GetNewDaughter();
        current->setvar(double(i)*2.);
    }

    std::vector<const Daughter*> filt1 = filter(col->daughters(),
                [] (const Daughter* d) {return d->var() > 2.;});

    std::vector<const Daughter*> filt2;
    for (unsigned int i=0; i<col->daughters().size(); i++)
    {
        const Daughter * current = &(col->daughters())[i];
        if (current->var() > 2.) filt2.push_back(current);
    }

    std::cout << "first filtered" << std::endl;
    for (const Daughter * c: filt1) c->print();
    std::cout << "second filtered" << std::endl;
    for (const Daughter * c: filt2) c->print();

    return 0;
}

As you can see, I defined two filters, one with the filter function and the other manually, which I expect to see the same result. However, I run the code 4 times, and each time, I got different results;

g++ -Wall -std=c++11 -O3 -fPIC main.cpp -o main
$ ./main
first filtered
printing from Daughter 4
printing from Daughter -2.68156e+154
Segmentation fault: 11
$ ./main
first filtered
printing from Daughter 4
printing from Daughter 0
Segmentation fault: 11
$ ./main
first filtered
printing from Daughter 4
printing from Daughter 2.31584e+77
Segmentation fault: 11
$ ./main
first filtered
printing from Daughter 4
printing from Daughter 6
printing from Daughter 8
second filtered
printing from Daughter 4
printing from Daughter 6
printing from Daughter 8

As you can see, the first 3 runs are completely rubbish for some reason, and the last one is as expected, but it seems to be completely random, so I believe I'm doing something wrong during the memory allocation. I would appreciate it if someone can show me what and why I am doing wrong and how should I change the code to avoid such instability.

Thanks!

Try to change:

std::vector<const T*> filter(std::vector<T> objects, FN func)

to

std::vector<const T*> filter(const std::vector<T>& objects, FN func)

imho, you create new instance (copy) of vector when you call filter. You 'filter' that new instance of vector, after the filter finishes the vector is deleted and, as result, std::vector<const Daughter*> filt1 has invalid pointers.

Evgeny was right. Just a small description of the problem. The thing is filter function returns the vector of pointers to the temporary objects that have been created on calling filter function (the first argument - vector). After the function finished his work, filt1 stores invalid pointers to the destroyed objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM