代码之家  ›  专栏  ›  技术社区  ›  bartop

begin()和end()不应该只对类的l值引用调用吗?

  •  1
  • bartop  · 技术社区  · 7 年前

    考虑以下代码:

    struct iterator{};
    
    struct foo {
        iterator begin() &{
            return {};        
        }
        iterator end() &{
            return {};        
        }
    };
    
    struct bar {
        iterator begin(){
            return {};        
        }
        iterator end(){
            return {};
        }
    };
    
    void baz(){
        //this obviously wouldn't compile
        //vvvvvvvvvvvvv
        //foo().begin();
        bar().begin();
    }
    

    这当然是玩具的例子 foo bar 结构模拟C++集合的工作。我的问题是是否有好的理由 begin end 对r值引用可调用的函数(如 酒吧 )? 或者我应该遵循 为了让代码更安全?据我所知,从临时集合获取迭代器通常是个坏主意。但另一方面,STL中的所有集合都用于l值和r值引用,所以我可能遗漏了一些东西

    live example

    0 回复  |  直到 7 年前
        1
  •  3
  •   Artyer    7 年前

    我想你想的是 begin 在生命周期结束的prvalue上调用,因此它导致 foo().begin() 作为一个悬挂的指针 foo() 已经被摧毁了。

    但事实并非总是如此。仅仅因为一个值是prvalue或xvalue并不意味着从调用到 foo::begin() iterator::operator* 那个 foo 对象将被销毁或清空。考虑一下:

    #include <utility>
    
    template<class T> void do_something_with(const T&);
    
    template<class T>
    void baz(T&& it) {
        auto begin = std::forward<T>(it).begin();
        auto end = std::forward<T>(it).end();
        for (; begin != end; ++begin) {
            do_something_with(*begin);
        }
    }
    
    void bar() {
        baz(foo());
        // Calls `baz<foo>(foo())`, with `decltype(it)` being `foo&&`
    }
    

    但这是一个非常有效的用例。不要将值类型(rvalue或lvalue)与生存期混淆。