为什么要对 map::find 应用不存在的键将返回一个C++中第一个值映射大小的迭代器



我有一个像下面的代码片段这样的用例,在getter返回的map中使用map::find来查找不存在的键实际上会找到一个迭代器,第一个值是map的大小(可能),因此不会按预期运行,等于map::end

这可能是因为我的地图是 getter 返回的地图。并在不将其分配给变量的情况下使用地图。因此,getter 返回的值可能已立即被破坏。

  1. 那么如果我的猜测是正确的呢?
  2. 为什么它返回地图的大小而不是它的结束迭代器?

    #include <iostream>
    #include <map>

    class B {
        long long id_;
        public:
        B() = default;
        explicit B(long long);
        ~B() = default;
    };
    B::B(long long int id) : id_(id) {}

    class A {
        std::string id_;
        std::map<long long, std::shared_ptr<B>> b_;
        public:
        A() = default;
        explicit A(std::string id);
        ~A() = default;
        const std::string &id() const;
        std::map<long long, std::shared_ptr<B>> b();
    };
    A::A(std::string id): id_(id) {
        b_[1] = std::make_shared<B>(1);
        b_[2] = std::make_shared<B>(2);
    }
    const std::string &A::id() const {
        return id_;
    }
    std::map<long long, std::shared_ptr<B>> A::b() {
        return b_;
    }

    int main() {
        std::shared_ptr<A> a = std::make_shared<A>("arst");
        if (a->b().find(3) != a->b().end()) {
            std::cout << a->b().find(3)->first << std::endl;
            std::cout << a->b().at(3) << std::endl;
        }
    }

运行如下:

clang --version
Apple LLVM version 10.0.0 (clang-1000.10.44.4)
Target: x86_64-apple-darwin18.2.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

带输出:

clang++ test.cc -std=c++11
./a.out
2
libc++abi.dylib: terminating with uncaught exception of type std::out_of_range: map::at:  key not found
[1]    64348 abort      ./a.out
std::map<long long, std::shared_ptr<B>> A::b();

您按值返回map,因此每次调用a->b()时,您都会创建地图的新副本b_这就是进行这种比较的原因:

a->b().find(3) != a->b().end()

。是未定义的行为,因为每次调用 b() 都会返回不同的映射,并且比较来自不同容器的迭代器是未定义的行为。

更改声明(和定义)以返回 ( const -) 引用:

const std::map<long long, std::shared_ptr<B>>& A::b();

您的函数A::b()按值返回映射。这意味着将返回一个副本,每次调用它时都是唯一的副本,并且其迭代器与任何其他副本的迭代器不兼容。

改为通过引用返回

最新更新