将非临时对象传递给 const 字符串引用仍然会打印垃圾

Passing non-temporary object to const string reference still prints garbage

提问人:BulGali 提问时间:7/16/2020 最后编辑:BulGali 更新时间:7/16/2020 访问量:112

问:

我试图自己为my_vec编写一个迭代器:

#define BEGIN true
#define END false
#include <vector>
#include <iostream>

template<typename Container>
class my_vec {
private:
    class iterator {
        const my_vec *this_vec;
        using iterator_type = typename std::vector<std::pair<int, const Container&>>::const_iterator;
        iterator_type itr;
    public:
        iterator(const my_vec &s, bool state) :
                this_vec(&s) {
            if (state == BEGIN) {
                itr = s.v.begin();
            } else { /*(state==END)*/
                itr = s.v.end();
            }
        }
        iterator& operator++() {
            itr++;
            return *this;
        }
        std::pair<int, const Container&> operator*() const {
            return std::make_pair(1, this_vec->dog);
        }
        bool operator!=(iterator other) const {
            return itr != other.itr;
        }
    }
    ;
public:
    std::string dog = "DOG";
    std::vector<std::pair<int, Container>> v;
    my_vec(int space) {
        v.reserve(space);
    }
    iterator begin() const {
        return iterator(*this, BEGIN);
    }
    iterator end() const {
        return iterator(*this, END);
    }
}
;

但是,在运行以下 main.cpp 时:

#include "my_vec.h"

int main() {
    my_vec<std::string> t(6);
    t.v.emplace_back(std::make_pair(1, "HELLO"));
    t.v.emplace_back(std::make_pair(2, "BYE"));
    t.v.emplace_back(std::make_pair(3, "CAT"));

    for (const auto &pair : t) {
        std::cout << pair.first << std::endl;
        std::cout << pair.second << std::endl;
    }
    return EXIT_SUCCESS;
}

预期输出为:

1
DOG
1
DOG
1
DOG

但是,实际输出为:

1

然后程序停止或打印垃圾。

似乎问题出在这个函数上:

std::pair<int, const Container&> operator*() const {
            return std::make_pair(1, this_vec->dog);
        }

为什么会发生这种行为,因为“狗”不是局部变量?

另外,如何在不更改运算符*的函数定义的情况下修复它?

C++ C++11 迭代器 按引用传递 构造函数

评论

1赞 Igor Tandetnik 7/16/2020
你一开始就充满了悬而未决的参考资料。 将对 temporary 的引用放入 ,则该 temporary 在分号处被销毁。想要拥有一个包含引用的向量是一件奇怪的事情 - 你确定你真的想要一个吗?vt.v.emplace_back(std::make_pair(1, "HELLO"));v
1赞 eerorika 7/16/2020
#define BEGIN true避免不必要的混淆,例如。
0赞 BulGali 7/16/2020
@IgorTandetnik 是的,你是对的。我会解决这个问题的。但是,请注意,operator* 的返回值是常量。

答:

5赞 Igor Tandetnik 7/16/2020 #1

std::make_pair(1, this_vec->dog)返回一个 类型的临时(我们给它起个名字) 。然后,类型的返回值(我们将其命名为 )构造自 ,从而绑定到 。最后,临时文件被销毁并返回给呼叫者,并持有悬空的引用。尝试使用此返回值时会表现出未定义的行为。tstd::pair<int, std::string>rstd::pair<int, const std::string&>tr.secondt.secondtr

来得及

return {1, this_vec->dog};

这将直接构造返回值,而无需中间临时对。