繁体   English   中英

为什么我不能创建一个引用向量?

[英]Why can't I make a vector of references?

当我这样做时:

std::vector<int> hello;

一切都很好。 但是,当我将其设为引用向量时:

std::vector<int &> hello;

我遇到了可怕的错误,比如

错误 C2528:“指针”:指向引用的指针是非法的

我想将一堆对结构的引用放入一个向量中,这样我就不必干预指针了。 为什么 vector 对此大发雷霆? 我唯一的选择是使用指针向量吗?

像向量这样的容器的组件类型必须是 可赋值的。 引用是不可分配的(您只能在声明它们时初始化它们一次,并且以后不能让它们引用其他东西)。 其他不可分配的类型也不允许作为容器的组件,例如vector<const int>是不允许的。

是的,你可以,寻找std::reference_wrapper ,它模仿参考但可分配,也可以“重新安装”

就其本质而言,引用只能在创建时设置; 即,以下两行具有非常不同的效果:

int & A = B;   // makes A an alias for B
A = C;         // assigns value of C to B.

此外,这是非法的:

int & D;       // must be set to a int variable.

但是,当您创建向量时,无法在创建时为其项目分配值。 您实际上只是在制作最后一个示例。

Ion Todirel 已经使用std::reference_wrapper提到了一个答案是肯定的。 从 C++11开始,我们有一种机制可以从std::vector检索对象并使用std::remove_reference删除引用。 下面给出了一个使用g++clang编译并带有选项-std=c++11并成功执行的示例。

    #include <iostream>
    #include <vector>
    #include <functional>
    
    class MyClass {
    public:
        void func() {
            std::cout << "I am func \n";
        }

        MyClass(int y) : x(y) {}

        int getval() {
            return x;
        }

    private: 
        int x;
    };

    int main() {
        std::vector<std::reference_wrapper<MyClass>> vec;

        MyClass obj1(2);
        MyClass obj2(3);

        MyClass& obj_ref1 = std::ref(obj1);
        MyClass& obj_ref2 = obj2;

        vec.push_back(obj_ref1);
        vec.push_back(obj_ref2);

        for (auto obj3 : vec) {
            std::remove_reference<MyClass&>::type(obj3).func();      
            std::cout << std::remove_reference<MyClass&>::type(obj3).getval() << "\n";
        }             
    }

TL; 博士

像这样使用std::reference_wrapper

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

int main()
{
    std::string hello = "Hello, ";
    std::string world = "everyone!";
    typedef std::vector<std::reference_wrapper<std::string>> vec_t;
    vec_t vec = {hello, world};
    vec[1].get() = "world!";
    std::cout << hello << world << std::endl;
    return 0;
}

演示

长答案

正如标准所暗示的,对于包含T类型对象的标准容器XT必须可以从XErasable

Erasable意味着以下表达式格式正确:

allocator_traits<A>::destroy(m, p)

A是容器的分配器类型, m是分配器实例, p*T类型的指针。 有关Erasable定义,请参见此处

默认情况下, std::allocator<T>用作向量的分配器。 使用默认分配器,要求等同于p->~T()的有效性(注意T是引用类型, p是指向引用的指针)。 但是, 指向引用的指针是非法的,因此表达式的格式不正确。

这是 C++ 语言的一个缺陷。 您不能获取引用的地址,因为尝试这样做会导致引用对象的地址,因此您永远无法获得指向引用的指针。 std::vector使用指向其元素的指针,因此存储的值需要能够被指向。 您将不得不使用指针。

boost::ptr_vector<int>将起作用。

编辑:建议使用std::vector< boost::ref<int> > ,因为您不能默认构造boost::ref ,所以它不起作用。

正如其他人所提到的,您最终可能会改用指针向量。

但是,您可能需要考虑使用ptr_vector代替!

我在 C++14 中找到了原因,“国际标准 ISO/IEC 14882:2014(E) 编程语言 C++”

[8.3.2-5.s1] 不应该有对引用的引用,没有引用数组,也没有指向引用的指针。

没有技术原因说明您不能拥有引用向量,它只是不是 API 的一部分,大概是为了使其类似于数组。 可以很容易地添加一个与引用一起工作的专业化,将它们存储为内部指针并在 API 中作为引用呈现:

vector<int&> ivref;
int i = 42;
ivref.push_back(i); // address of i is stored
ivref.front() = 43; // i is set to 43
ivref.push_back(44); // Marked deleted for rvalue references 
ivref.resize(10);    // Marked deleted for vector of references

正如其他评论所暗示的那样,您仅限于使用指针。 但如果有帮助,这里有一种避免直接面对指针的技术。

您可以执行以下操作:

vector<int*> iarray;
int default_item = 0; // for handling out-of-range exception

int& get_item_as_ref(unsigned int idx) {
   // handling out-of-range exception
   if(idx >= iarray.size()) 
      return default_item;
   return reinterpret_cast<int&>(*iarray[idx]);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM