вектор shared_ptrs, возвращая его из функции и изменяя его

По сути, я хочу, чтобы 2 моих класса делились некоторыми данными, которые я хочу иметь в виде вектора объектов shared_ptr.

Я сократил свой код до следующего простого компилируемого примера.

Я хочу, чтобы объект A просматривал данные, которые были инициализированы в объекте B. Однако, когда я пытаюсь выполнить push_back() внутри метода A, он не изменил размер вектора объектов shared_ptr в B. (В момент строка с комментарием «Это точка интереса».)

Какой подход мне нужно использовать, чтобы получить эту функциональность, или я на неправильном пути. (новичок С++ здесь)

#include <memory>
#include <vector>
#include <iostream>
using std::cout;
using std::endl;
class DataClass {
    public:
        int i_;
};
class B {
    public:
        // constructor:
        B() : my_data_(std::vector<std::shared_ptr<DataClass> >()) {
            my_data_.push_back(std::shared_ptr<DataClass> (new DataClass));
            my_data_.push_back(std::shared_ptr<DataClass> (new DataClass));
            my_data_[0]->i_ = 1;
            my_data_[1]->i_ = 2;
            cout<<my_data_.size()<<endl;
        };

        // return the data
        std::vector< std::shared_ptr<DataClass> > get_my_data() {
            return my_data_;
        };

        // check the data:
        void CheckData() {
            cout<<my_data_.size()<<endl; // This is the point of interest
        };
        // member variable
        std::vector< std::shared_ptr<DataClass> > my_data_;
};
class A {

    public:
        void start() {
            // begin interaction with B class:
            B b;

            // get the vector of data pointers:
            a_has_data_ = b.get_my_data();

            // modify some of the data:
            a_has_data_.push_back(std::shared_ptr<DataClass> (new DataClass));
            a_has_data_[2]->i_ = 42;

            b.CheckData(); 
        };
    private:
    std::vector< std::shared_ptr<DataClass> > a_has_data_;

};
int main() {
    A a;
    a.start();
}

person CptLightning    schedule 01.03.2013    source источник
comment
Вы делаете копию вектора. Вместо этого верните его по ссылке: std::vector< std::shared_ptr<DataClass> >& get_my_data()   -  person Peter Wood    schedule 02.03.2013
comment
@Peter Кажется, это не работает, я думаю, это потому, что я пытаюсь сохранить ссылку как переменную-член в A? это работает, если я делаю: b.get_my_data().push_back()...и т. д., однако это не работает в форме: a_has_data_.push_back() даже после вашего предложения.   -  person CptLightning    schedule 02.03.2013
comment
Возможно, вы захотите переосмыслить свой дизайн. Возможно, объединить два класса или вместо этого оставить данные в A.   -  person Peter Wood    schedule 02.03.2013


Ответы (3)


Вы возвращаете копию вектора. Вам нужно вернуть ссылку на данные:

// return the data
std::vector< std::shared_ptr<DataClass> >& get_my_data()
{
        return my_data_;
};

То есть A обращается к вектору b, а не к его копии.

person juanchopanza    schedule 01.03.2013
comment
Кажется, это не работает, я думаю, это потому, что я пытаюсь сохранить ссылку как переменную-член в A? это работает, если я делаю: b.get_my_data().push_back()...и т. д., однако это не работает в форме: a_has_data_.push_back() даже после вашего предложения. - person CptLightning; 02.03.2013
comment
@CptLightning, тогда вы можете сохранить B в качестве элемента данных A и удалить элемент векторных данных. Проблема в том, что вы пытаетесь соединить две вещи с разным временем жизни: B, который живет в области A::start(), и A::a_has_data. - person juanchopanza; 02.03.2013
comment
о да, теперь я вижу конфликт жизней. Спасибо - person CptLightning; 02.03.2013

a_has_data_.push_back(std::shared_ptr<DataClass> (new DataClass));

С типом возвращаемого значения «копирование», приведенный выше оператор изменит файл a_has_data_. А в b.CheckData(); вы фактически проверяете размер b's члена.

Введите функцию-член в A, чтобы проверить размер вектора, и вы должны увидеть увеличение.

person Mahesh    schedule 01.03.2013

Здесь в

 std::vector< std::shared_ptr<DataClass> > get_my_data()

Значение получается с возвратом по значению, поэтому создается новый объект. См. следующую реализацию. Он решает вашу проблему, отправляя указатель.

#include <tr1/memory>
#include <vector>
#include <iostream>
using namespace std;
using std::cout;
using std::endl;
class DataClass {
    public:
        int i_;
};
class B {
    public:
        // constructor:
        B() : my_data_(std::vector<tr1::shared_ptr<DataClass> >()) {
            my_data_.push_back(tr1::shared_ptr<DataClass> (new DataClass));
            my_data_.push_back(tr1::shared_ptr<DataClass> (new DataClass));
            my_data_[0]->i_ = 1;
            my_data_[1]->i_ = 2;
        };

        // return the data
        std::vector< tr1::shared_ptr<DataClass> >* get_my_data() {
            return &my_data_;
        };

        // check the data:
        void CheckData() {
            cout<<my_data_.size()<<endl; // This is the point of interest
        };
        // member variable
        std::vector< tr1::shared_ptr<DataClass> > my_data_;
};
class A {

    public:
        void start() {
            // begin interaction with B class:
            B b;

            // get the vector of data pointers:
            a_has_data_ = b.get_my_data();

            // modify some of the data:
            b.CheckData(); 
            a_has_data_->push_back(tr1::shared_ptr<DataClass> (new DataClass));
            (*a_has_data_)[2]->i_ = 42;
            b.CheckData(); 
        };
    private:
    std::vector< tr1::shared_ptr<DataClass> >* a_has_data_;

};
int main() {
    A a;
    a.start();
}

Примечание. Я изменил код на tr1/memory, так как у меня старый gcc.

person Krish    schedule 01.03.2013
comment
При выходе из области A::start() A::a_has_data_ остается в виде висящего указателя. - person juanchopanza; 02.03.2013
comment
Ну, вам нужно написать деструктор для него. Я предположил, что это подразумевается, если это указатель :) - person Krish; 02.03.2013
comment
Деструктор тут ни при чем. `A::a_has_dataДеструктор не решает проблему. Это не связано. - person juanchopanza; 02.03.2013
comment
Я думаю, лучше изменить дизайн. - person Krish; 02.03.2013
comment
Да, я думаю, это единственный способ. - person juanchopanza; 02.03.2013