Как я могу сделать это с помощью Smart Pointers?

Вот чего я пытаюсь достичь:

#include <iostream>
using std::cout;

#include <vector>
using std::vector;

int main()
{
    vector<int> a {3, 7};

    int *p = &a.at (0); //assign 3

    for (int i = 0; i < 10; ++i) //swap and print (3,7,3...)
    {
        p = (*p == a.at (0) ? &a.at (1) : &a.at (0));
        cout << *p << '\n';
    }
}

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

Я попытался заменить указатели здесь std::unique_ptr а также std::shared_ptr в двух отдельных тестах, используя reset переключаться, причем оба дают случайные числа после первого, как и ожидалось.

Далее я попробовал с std::weak_ptr как это выглядит, что мне нужно, хотя интерфейс не так уж похож. Из того, что я видел, единственный способ использовать это через lock()поэтому я попытался предугадать lock(). на вызовы reset и добавив его к разыменованию, но это потерпело крах.

Как я могу использовать std::weak_ptr вместо необработанного указателя, или я могу как-то использовать один из других?

3 ответа

Решение

Вместо того, чтобы использовать необработанные указатели для этого типа операции индексирования, я думаю, что вы должны изучить использование std::vector::iteratorимея в виду, что любая операция вставки в std::vector может сделать недействительным итератор. Например, вы можете сделать следующее:

typedef std::vector<int>::iterator iter_t;

vector<int> a {3, 7};

iter_t p = iter_t(&a.at(0)); //assign 3

for (int i = 0; i < 10; ++i) //swap and print (3,7,3...)
{
    p = (*p == a.at(0) ? iter_t(&a.at(1)) : iter_t(&a.at(0)));
    cout << *p << '\n';
}

Умные указатели не намного лучше по определению. Они полезны, только если им нужно управлять памятью, на которую они указывают.

Поскольку ваши указатели просто указывают на элементы в vectorВам не нужны умные указатели вообще. Большинство умных указателей будут пытаться удалить память, на которую они указывают, когда они выходят за рамки видимости, что в этом случае приведет к появлению носовых демонов.

Имейте в виду, однако, что изменение размера вектора может привести к тому, что все ваши указатели станут недействительными. Убедитесь, что вы не добавляете и не удаляете элементы, пока указатели находятся в области видимости.

В этом случае, если игроки ходят по очереди, я бы, вероятно, вообще не использовал указатели, а что-то вроде этого:

int main()
{
    vector<int> players {3, 7};

    int current_player = 0;

    while (!game_over())
    {
        cout << players[current_player] << '\n';
        current_player = (current_player + 1) % players.size();
    }
}

Просто понял, что вы можете иметь в виду, что вы хотите иметь умный указатель на int внутри вектора, а не менять целые числа в векторе на умные указатели. Я бы не стал этого делать. Я бы использовал итераторы вектора:

for (int i = 0; i < 10; ++i) {
  auto it = it.begin() + (i % 2 ? 1:0);
  f(*it);
}

Использование общего, уникального или любого другого указателя внутри вашего вектора приведет к плохим, плохим и плохим вещам. Использование необработанных указателей также не гарантируется, так как они ничего не указывают на то, на что они указывают. С другой стороны, итераторы вектора, хотя, возможно, и реализованы в виде необработанных указателей, имеют четкие, документированные правила их использования, которые вы можете документировать в своем коде, используя их.

Не забывайте, что "умный указатель" включает в себя итераторы.

Другие вопросы по тегам