Стандартная практика для создания «вектора ссылок» Использование только стандартных библиотек

Я хотел бы создать объект, поместить объект в vectorи по-прежнему сможет изменять тот же объект, получая доступ только к vector, Тем не менее, я понимаю, что когда объект push_back() к vectorобъект на самом деле копируется в vector, В результате доступ к объекту в vector просто получит доступ к похожему, но другому объекту.

У меня есть знания новичка в C, поэтому я знаю, что могу создать указатель на объект и сделать вектор из указателей. например vector<Object *>, Тем не менее, кажется, как будто указатели являются обескураженный в C ++ и ссылки являются предпочтительными. Еще, Я не могу сделать вектор ссылок.

Я хочу использовать только стандартные библиотеки, поэтому boost мне запрещено.

Я слышал об умных указателях. Тем не менее, создается впечатление, что существует несколько типов интеллектуальных указателей. Разве это не было бы излишним для этой цели? Если умные указатели действительно являются ответом, то как определить, какой из них использовать?

Итак, мой вопрос: Какова стандартная практика для создания вектора ссылок / указателей на объекты?

Другими словами, хотелось бы, чтобы приведенный ниже (псевдо) код работал.

#include <iostream>
#include <cstdlib>
#include <vector>

using namespace std;

class Object
{
public:
int field;
};

vector<Object> addToVector(Object &o)
{
vector<Object> v;
v.push_back(o);
v[0].field = 3; // I want this to set o.field to 3.

return v;
}

int main()
{
Object one;
one.field = 1;
cout << one.field << endl; // 1 as expected

Object &refone = one;
refone.field = 2;
cout << one.field << endl; // 2 as expected

vector<Object> v = addToVector(one);

cout << v[0].field << endl; // 3 as expected

cout << one.field << endl; // I want to get 3 here as well, as opposed to 2.return 0;
}

0

Решение

Я хотел бы создать объект, поместить объект в вектор и при этом иметь возможность изменять тот же объект, получая доступ только к вектору. Тем не менее, я понимаю, что когда объект push_back() в вектор, объект фактически копируется в вектор. В результате доступ к объекту в векторе будет просто обращаться к похожему, но другому объекту.

Я почти уверен, что это не то, что вы хотите или «должны» хотеть. Простите мне, что открываю мой ответ, но если у вас нет веских причин для этого, вы, вероятно, не хотите этого делать.

Для этого — вектор со ссылками — чтобы вы работали должен гарантировать, что ссылочные объекты не будут перемещены или разрушены, пока вы держите ссылки на них. Если они есть в векторе, убедитесь, что вектор не изменен. Если они есть в стеке, как в вашем примере, то не позволяйте вектору ссылок или его копии покинуть этот стек. Если вы хотите хранить их в каком-то контейнере, используйте std::list (это итераторы — в основном указатели — не становятся недействительными при вставке или удалении элементов).

Вы уже заметили, что у вас не может быть вектора «реальных» ссылок. Поэтому причина в том, что ссылки не могут быть назначены. Рассмотрим следующий код:

int a = 42;
int b = 21;
int & x = a; // initialisation only way to bind to something
int & y = b;
x = y;
b = 0;

После этого значение, которое вы получаете от x будет 21, потому что назначение не изменило ссылку (быть связанным с b) но указанный объект, a, Но std::vector явно требует этот.

Теперь вы можете установить и написать обертку вокруг указателя, как …

template<typename T>
struct my_ref {
T * target;
// don't let one construct a my_ref without valid object to reference to
my_ref(T & t) : target(&t) {}
// implicit conversion into an real reference
operator T &(void) {
return *target;
}
// default assignment works as expected with pointers
my_ref & operator=(my_ref const &) = default;
// a moved from reference doesn't make sense, it would be invalid
my_ref & operator=(my_ref &&) = delete;
my_ref(my_ref &&) = delete;
// ...
};

… но это довольно бессмысленно, так как std::reference_wrapper уже обеспечивает именно это:

int main (int, char**) {
int object = 21; // half of the answer
vector<reference_wrapper<int>> v;
v.push_back(object);
v[0].get() = 42; // assignment needs explicit conversion of lhs to a real reference
cout << "the answer is " << object << endl;
return 0;
}

(Пример живи здесь)

Теперь можно поспорить, зачем использовать обёртку вокруг указателя типа std::reference_wrapper когда можно также напрямую использовать указатель. ИМО указатель, имеющий возможность быть nullptr, изменяет семантику кода: если у вас есть необработанный указатель, он мог быть недействительным Конечно, вы можете просто предположить, что это не так, или указать это где-нибудь в комментариях, но в конце концов вы полагаетесь на то, что не гарантировано кодом (и это обычно приводит к ошибкам).

Если элемент вашего вектора может «ссылаться» на объект или быть недействительным, тогда все еще необработанные указатели не являются первым выбором (для меня): когда вы используете элемент из вашего вектора, который является действительным, тогда объект, на который он ссылается, фактически ссылки из нескольких мест в вашем коде; это общее. «Основная» ссылка на объект должна быть std::shared_ptr и элементы вашего вектора std::weak_ptrs. Затем вы можете (потокобезопасно) получить действительную «ссылку» (общий указатель), когда вам нужно, и отбросить ее, когда закончите:

auto object = make_shared<int>(42);
vector<weak_ptr<int>> v;
v.push_back (object);

// ... somewhere later, potentially on a different thread
if (auto ref = v[0].lock()) {
// noone "steals" the object now while it's used here
}
// let them do what they want with the object, we're done with it ...

Наконец, пожалуйста, примите мой ответ с небольшим количеством соли, большая часть которого основана на моем мнении (и опыте) и может не считаться «стандартной практикой».

1

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector