创建"参考文献的标准实践"仅使用标准库

时间:2015-08-19 20:29:57

标签: c++ pointers vector reference standard-library

我想创建一个对象,将对象放入vector,并且仍然可以通过仅访问vector来修改同一个对象。但是,据我所知,当一个对象push_back()vector时,该对象实际上会被复制到vector中。因此,访问vector中的对象只会访问类似但不同的对象。

我在C中有初学者的知识,所以我知道我可以创建一个指向该对象的指针,并创建一个指针向量。例如vector<Object *>。但是,在C ++中似乎pointers discouragedreferences are preferred。然而,I cannot make a vector of references

我希望只使用标准库,因此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;
}

1 个答案:

答案 0 :(得分:1)

  

我想创建一个对象,将对象放入向量中,并且仍然可以通过仅访问向量来修改同一个对象。但是,据我所知,当一个对象是push_back()向量时,该对象实际上被复制到向量中。因此,访问向量中的对象只会访问类似但不同的对象。

我几乎可以肯定这不是你想要的东西,或者&#34;应该&#34;想。请原谅我直接打开我的答案,但除非你有充分的理由这样做,否则你可能不想这样做。

为此 - 带引用的向量 - 为工作必须保证引用的对象在您持有对它们的引用时不会被移动或被破坏。如果将它们放在矢量中,请确保矢量未调整大小。如果你在堆栈中有它们,就像在你的例子中那样,那么不要让引用的向量或它的副本离开那个堆栈帧。如果要将它们存储在某个容器中,请使用std::list(它的迭代器 - 基本指针 - 插入或删除元素时不会失效)。

你已经注意到你不能拥有&#34;真实&#34;引用。因此,原因是参考文献不可分配。请考虑以下代码:

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)但引用的对象{{1 }}。但是std::vector explicitly requires这个。

你现在可以设置并在像...这样的指针周围写一个包装器。

a

...但这是毫无意义的,因为std::reference_wrapper已经提供了这一点:

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;
  // ...
};

Example live here

现在有人可能会争论为什么在可以直接使用指针的情况下在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; } 之类的指针周围使用包装器。 IMO指针,具有std::reference_wrapper的能力,改变了代码的语义:当你有一个原始指针时,它可能无效。当然,你可以假设它不是,或者把它放在评论的某个地方,但最后你依赖于代码无法保证的东西(这种行为通常会导致错误)。

如果你的矢量元素可以&#34;引用&#34;一个对象或无效,那么仍然是原始指针不是第一个选择(对我来说):当你使用向量中有效的元素时,它引用的对象实际上是从代码中的多个位置引用的;它是共享的。 &#34;主要&#34;那么对象的引用应该是std::shared_ptr和向量std::weak_ptr的元素。然后,您可以(线程安全)获取有效的&#34;参考&#34; (共享指针)当你需要并在完成后删除它:

nullptr

最后,请把我的答案弄得一塌糊涂,其中大部分都是基于我的观点(和经验),可能不算作#34;标准练习&#34;。