C ++ Я хочу избежать указателей и вместо этого использовать STL и ссылки для поддержки небольшого кэша данных - PullRequest
0 голосов
/ 16 ноября 2018
#include <iostream>
#include <vector>
#include <string>


struct A
{
    std::string a;
    std::vector<A> avector;
};

typedef std::vector<A> Avector;

A& func(A& x)
{
   A& ret = x.avector[0];
   return ret;
}

int main()
{
   A genesis = { "Parent", std::vector<A>() };
   A l1 = { "Child1", std::vector<A>() };
   A l2 = { "Child2", std::vector<A>() };

   genesis.avector.push_back(l1);
   genesis.avector.push_back(l2);

   std::cout << "l1: " << l1.a << std::endl; //shows "Child1"
   std::cout << "l2: " << l2.a << std::endl; //shows "Child2"

   A& lx = func(genesis);
   lx.a = "Childx";

   std::cout << "l1: " << l1.a << std::endl; //!!still shows "Child1"

   return 1;
}

Итак, в общем, я хочу иметь единственную копию данных в целом, т.е. объект Genesis и еще два объекта l1 и l2 как объект Genesis.avector

Однако я не могуизмените это позже, так как каждый раз, когда я изменяю копии, но не фактические данные объекта Genesis.

Спасибо за вашу помощь!

Ответы [ 2 ]

0 голосов
/ 16 ноября 2018
I was able to make this work with introducing a constructor and some help from @Sorin.

    #include <iostream>
    #include <vector>
    #include <string>


    struct A
    {
        std::string a;
        std::vector<A> avector;
        A(std::string aa)
        {
           a = aa;
        }
    };

    typedef std::vector<A> Avector;

    A& func(A& x)
    {
       return x.avector[0];
    }

    int main()
    {
       A genesis("Parent");
       genesis.avector.push_back(static_cast<A>("Child1"));
       genesis.avector.push_back(static_cast<A>("Child2"));

       A& l1 = genesis.avector[0];
       A& l2 = genesis.avector[1];

       std::cout << "l1: " << l1.a << std::endl;
       std::cout << "l2: " << l2.a << std::endl;

       A& lx = func(genesis);
       lx.a = "Childx";

       std::cout << "l1: " << genesis.avector[0].a << std::endl;
       std::cout << "l2: " << l2.a << std::endl;
       return 1;
    }

Выход:

l1: Child1

l2: Child2

l1: Childx

l2: Child2

0 голосов
/ 16 ноября 2018

В вашем коде:

A genesis = { "Parent", std::vector<A>() };
A l1 = { "Child1", std::vector<A>() };
A l2 = { "Child2", std::vector<A>() };

genesis .avector.push_back(l1);
genesis .avector.push_back(l2);

У вас есть 5 экземпляров. 3, которые вы объявляете, и 2 копии, которые у вас есть в вашем векторе.

Таким образом, более правильный (но возможно, ошибочный) способ сделать это будет:

A genesis = { "Parent", std::vector<A>() };
genesis .avector.emplace_back("Child1", std::vector<A>());
genesis .avector.emplace_back("Child2", std::vector<A>());

A& l1 = genesis.avector[0];
A& l2 = genesis.avector[1];

Теперь у вас есть только 3 экземпляра. l1 и l2 являются ссылками на элементы в векторе, поэтому изменения в них будут отражаться и в векторе.

Я сказал, что это возможно глючит. Когда вы изменяете вектор (добавляя что-то еще), ему, возможно, придется перераспределить, поэтому любые ваши ссылки будут недействительными, а результатом будет неопределенное поведение.

Если вам нужно изменить вектор, я бы сделал vector<unique_ptr<A>>. Затем A& l1 = *genesis.avector[0], и это будет действовать до тех пор, пока элемент не будет удален из вектора.

Вы также можете попробовать std::reference_wrapper вместо unique_ptr, если хотите, чтобы объекты жили в стеке. Я бы попытался избежать этого, так как более очевидно, что что-то разрушается при удалении из вектора, чем когда локальная переменная выходит из области видимости.

...