Zsw*_*Zsw 7 c++ pointers reference vector standard-library
我想创建一个对象,将该对象放入vector,并且仍然能够通过仅访问vector. 但是,我知道当一个对象指向push_back()a时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;
}
Run Code Online (Sandbox Code Playgroud)
我想创建一个对象,将对象放入向量中,并且仍然能够通过仅访问向量来修改同一对象。然而,我明白,当一个对象到
push_back()一个向量时,该对象实际上被复制到向量中。因此,访问向量中的对象将仅访问相似但不同的对象。
我几乎可以肯定这不是您想要或“应该”想要的。请原谅我直接打开我的答案,但除非你有充分的理由这样做,否则你可能不想这样做。
为此 - 带有引用的向量 - 要工作,您必须保证引用的对象在您持有对它们的引用时不会被移动或破坏。如果您将它们放在向量中,请确保该向量未调整大小。如果像示例中那样将它们放在堆栈上,则不要让引用向量或其副本离开该堆栈帧。如果你想将它们存储在某个容器中,请使用 a 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;
Run Code Online (Sandbox Code Playgroud)
之后,您从中获得的值x将是 21,因为赋值没有更改引用(要绑定到b),而是更改了引用的对象a。但 astd::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;
// ...
};
Run Code Online (Sandbox Code Playgroud)
...但这毫无意义,因为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;
}
Run Code Online (Sandbox Code Playgroud)
(这里的例子)
现在,人们可能会争论为什么要在指针周围使用包装器,就像std::reference_wrapper我们也可以直接使用指针一样。在我看来,指针能够nullptr改变代码的语义:当你有一个原始指针时,它可能是无效的。当然,您可以假设它不是,或者将其放在注释中的某个位置,但最终您会依赖于代码无法保证的东西(这种行为通常会导致错误)。
如果向量的元素可以“引用”对象或无效,那么原始指针仍然不是首选(对我来说):当您使用向量中有效的元素时,它引用的对象是实际上是从代码的多个位置引用的;它是共享的。对对象的“主要”引用应该是 astd::shared_ptr和向量 s 的元素std::weak_ptr。然后,您可以(线程安全)在需要时获取有效的“引用”(共享指针)并在完成后删除它:
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 ...
Run Code Online (Sandbox Code Playgroud)
最后,请对我的回答持保留态度,其中大部分是基于我的观点(和经验),可能不算是“标准做法”。