如何安全地引用 std::vector 元素?

Posted

技术标签:

【中文标题】如何安全地引用 std::vector 元素?【英文标题】:How I can safely reference to an std::vector element? 【发布时间】:2021-05-16 22:31:34 【问题描述】:

我想创建一个为其他结构保持更高状态的结构。

我尝试这样创建它,但我最近发现返回指向 std::vector 元素的指针并不安全,因为该指针可以更改。

struct Foo 
  std::string &context;
  std::string content;

  Foo(std::string &context, std::string content) : context(context), content(content) 


struct Bar 
  std::string context;
  std::vector<std::string> manyFoos;

  Foo* addFoo(std::string content) 
    manyFoos.emplace_back(context, content);
    return &manyFoos[manyFoos.size() - 1];
  


struct Example 
  Bar bar;
  Foo* fooA;
  Foo* fooB;

  Example() 
    fooA = bar.addFoo("Hello");
    fooB = bar.addFoo("World");
  

有什么好的和安全的方法来做到这一点?

【问题讨论】:

使用其他容器代替 std::vector? ^^ 例如std::list&lt;T&gt; 标准库有什么替代品吗? 我刚才提到了一个 你可以拥有share_ptr的vector并返回weak_ptr,这样你可以确保正确的引用。 【参考方案1】:

有什么好的和安全的方法来做到这一点?

保存这对夫妇(矢量参考,Foo 的索引),假设 Foos 只添加在后面。

加上一点语法糖:

struct Bar 
  std::string context;
  std::vector<Foo> manyFoos;

  struct FooProxy
  
    std::vector<Foo>& foos;
    std::vector<Foo>::size_type index;
    operator Foo()  return foos[index]; 
  ;

  auto addFoo(std::string content) 
    manyFoos.emplace_back(context, content);
    return FooProxymanyFoos, manyFoos.size()-1;
  
;

Live example

【讨论】:

【参考方案2】:

你可以拥有shared_ptr的向量并返回weak_ptr,这样你可以确保正确引用

#include <iostream>
#include <vector>
#include <memory>

struct Foo 
    std::string &context;
    std::string content;

    Foo(std::string &context, std::string content) : context(context), content(content) 
;

struct Bar 
    std::string context;
    std::vector<std::shared_ptr<Foo>> manyFoos;

    std::weak_ptr<Foo> addFoo(std::string content) 
        auto foo = std::make_shared<Foo>(context, content);
        manyFoos.emplace_back(foo);
        return foo;
    
;

void printFoo(std::weak_ptr<Foo> foo)

    // Here we are checking weak_ptr expiry
    std::cout << (foo.expired() ? "Foo Expired" : foo.lock()->content) << std::endl;


int main() 
    Bar bar;
    std::weak_ptr<Foo> fooA;
    std::weak_ptr<Foo> fooB;

    fooA = bar.addFoo("Hello");
    fooB = bar.addFoo("World");

    printFoo(fooA);
    printFoo(fooB);

    // erase last element
    bar.manyFoos.pop_back();
    printFoo(fooB);
    return 0;

输出:

Hello
World
Foo Expired

【讨论】:

以上是关于如何安全地引用 std::vector 元素?的主要内容,如果未能解决你的问题,请参考以下文章

使用对 std::vector 的某些元素的引用,或这些元素在向量中的位置来迭代它们

为 std::vector 键入安全索引值

如何告诉 auto 推断 vector<bool> 元素的非引用类型

如何正确地从 C++ 中的迭代器返回对对象的引用

如何确定`range :: view`对象和`std :: vector`之间的等价?

std::thread 通过引用传递向量元素