为什么我不能制作参考文献?

Col*_*len 328 c++ stl reference vector container-data-type

当我这样做:

std::vector<int> hello;
Run Code Online (Sandbox Code Playgroud)

一切都很好.但是,当我把它作为引用的向量时:

std::vector<int &> hello;
Run Code Online (Sandbox Code Playgroud)

我得到了可怕的错误

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

我想把一堆结构的引用放到一个向量中,这样我就不必插入指针了.为什么矢量会对此发脾气?我唯一的选择是使用指针向量吗?

new*_*cct 315

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

  • 实际上,这是"实际"原因.关于T*不可能出现T的错误是U&只是T必须可分配的违反要求的副作用.如果vector能够精确检查类型参数,那么它可能会说"违反要求:T&not assignable" (16认同)
  • 是的,std :: vector <std :: vector <int >>是正确的,std :: vector是可分配的. (8认同)
  • 这不再是事实。从C ++ 11开始,对element的唯一与操作无关的要求是“可擦除的”,而引用不是。参见/sf/ask/2320109361/。 (6认同)
  • 在http://www.boost.org/doc/libs/1_39_0/doc/html/Assignable.html上检查可分配的概念除交换之外的所有操作对引用都有效. (2认同)
  • @johnbakers:您正在修改引用指向的内容,而不是引用本身。修改引用本身可以让引用指向其他内容,而这对于 C++ 引用来说是不可能的。 (2认同)

Ion*_*rel 111

是的,您可以,寻找std::reference_wrapper,模仿参考但可分配,也可以"重新安排"

  • 有没有办法在尝试访问此包装器中的类实例的方法时首先调用`get()`?例如`reference_wrapper <MyClass> my_ref(...); my_ref.get().doStuff();`不是很像引用. (4认同)
  • 通过返回引用,它是不是可以强制转换为Type本身? (3认同)
  • 是的,但这需要一个上下文,该上下文暗示需要进行转换。成员访问不能这样做,因此需要`.get()`。* timdiels *想要的是“操作员”。查看有关此问题的最新建议/讨论。 (3认同)

Jam*_*ran 30

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

int & A = B;   // makes A an alias for B
A = C;         // assigns value of C to B.
Run Code Online (Sandbox Code Playgroud)

此外,这是非法的:

int & D;       // must be set to a int variable.
Run Code Online (Sandbox Code Playgroud)

但是,在创建矢量时,无法在创建时为其项目指定值.你基本上只是制作了最后一个例子.

  • "当你创建一个向量时,没有办法在创建时为它的项目赋值"我不明白你的意思是什么.什么是"它的创造物品"?我可以创建一个空矢量.我可以使用.push_back()添加项目.您只是指出引用不是默认构造的.但我绝对可以拥有不是默认构造的类的向量. (10认同)
  • James Curran,那里没有默认施工.push_back只是placement-news A进入预分配的缓冲区.请参见此处:http://stackoverflow.com/questions/672352/how-is-dynamic-memory-managed-in-stdvector.请注意,*my*claim只是该向量可以处理非默认构造类型.当然,我没有声称它可以处理T&(当然不能). (3认同)
  • std :: vector <T>的元素ype不需要是默认可构造的.你可以写struct A {A(int); 私人:A(); }; vector <A> a; 很好 - 只要你不使用这样的方法,要求它是默认的可构造的(如v.resize(100); - 但你需要做v.resize(100,A(1));) (2认同)

Ste*_*hen 27

Ion Todirel已经提到了答案YES使用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";
    }             
}
Run Code Online (Sandbox Code Playgroud)

  • 我在这里看不到`std :: remove_reference <>`中的值.`std :: remove_reference <>`的要点是允许你写"类型T,但如果它是一个则不作为引用".因此`std :: remove_reference <MyClass&> :: type`与编写`MyClass`相同. (12认同)
  • 根本没有任何价值-您只需为(MyClass obj3:vec)std :: cout &lt;&lt; obj3.getval()&lt;&lt;“ \ n”;`**(或for(const MyClass&obj3) :vec)`,如果您声明`getval()`const,则应如此)。 (2认同)

Dre*_*ann 14

boost::ptr_vector<int> 将工作.

编辑:是一个使用的建议std::vector< boost::ref<int> >,这将无法工作,因为你不能默认构建一个boost::ref.

  • 但是你可以有一个矢量或非默认构造类型,对吧?您只需要小心不要使用默认的ctor.矢量 (8认同)
  • 小心,Boost的指针容器独占所有者.[quote](http://www.boost.org/doc/libs/1_57_0/libs/ptr_container/doc/ptr_container.html#motivation):"当你确实需要共享语义时,这个库不是你需要的." (5认同)

Ada*_*eld 12

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

  • "语言中的缺陷"太强大了.这是设计的.我认为不需要向量使用指向元素的指针.但是,要求元素可分配.参考文献不是. (53认同)

iva*_*ult 8

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;
}
Run Code Online (Sandbox Code Playgroud)

Demo

长答案

作为标准建议,对于X包含类型对象的标准容器TT必须Erasable来自X

Erasable 表示以下表达式格式正确:

allocator_traits<A>::destroy(m, p)
Run Code Online (Sandbox Code Playgroud)

A是容器的分配器类型,m是分配器实例,并且p是type的指针*T。见这里Erasable定义。

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