代码之家  ›  专栏  ›  技术社区  ›  Eamon Nerbonne

围绕C++对临时非const引用的限制

  •  3
  • Eamon Nerbonne  · 技术社区  · 15 年前

    这意味着通常,此类的对象是通过引用传递的。

    如果一个实例只需要一次,最自然的方法是在需要的地方构造它们(可能使用工厂方法或构造函数),然后将草稿行传递给使用方法。使用者的方法签名使用按引用传递,因为他们不知道这是唯一的用途,但是工厂方法和构造函数按值返回-并且不能按引用传递未命名的临时对象。

    有没有办法避免用讨厌的临时变量阻塞代码?我希望避免以下情况:

    scratchpad_t<typeX<typeY,potentially::messy>, typename T> useless_temp = factory(rng_parm);
    xyz.initialize_computation(useless_temp);
    

    我可以做草稿 mutable const & ,但我觉得这并不是最佳实践,因为这是误导性的,我不能对我不能完全控制的类这样做。传递rvalue引用需要向scratchpad的所有使用者添加重载,这有点违背了它的目的——拥有清晰简洁的代码。

    考虑到性能并不重要(但代码大小和可读性很重要), 传递这种草稿行的最佳实践方法是什么? 使用C++ 0x特性是可以的 必修的 但最好只有C++ 03的特征就足够了。

    要清楚的是,使用一个临时的是可行的,这只是不幸的混乱的代码,我想避免。如果从不给临时文件起名字,那么它显然只使用一次,而且要读取的代码行越少越好。而且,在构造函数的初始值设定项中,不可能声明临时值。

    5 回复  |  直到 15 年前
        1
  •  4
  •   fredoverflow    15 年前

    虽然向接受非常量引用的函数传递r值是不合适的,但是调用r值上的成员函数也是可以的,但是成员函数不知道它是如何被调用的。如果返回对当前对象的引用,则可以将右值转换为左值:

    class scratchpad_t
    {
        // ...
    
    public:
    
        scratchpad_t& self()
        {
            return *this;
        }
    };
    
    void foo(scratchpad_t& r)
    {
    }
    
    int main()
    {
        foo(scratchpad_t().self());
    }
    

    注意呼叫 self() 生成左值表达式,即使 scratchpad_t

    如果我错了,请纠正我,但是Rvalue引用参数不接受左值引用,因此使用它们需要向scratchpad的所有使用者添加重载,这也是不幸的。

    你可以用模板。。。

    template <typename Scratch> void foo(Scratch&& scratchpad)
    {
        // ...
    }
    

    foo 使用rvalue参数, Scratch 草稿行\ ,因此 Scratch&& scratchpad_t&& .

    使用左值参数, 将被推断为 scratchpad_t& ,由于引用折叠规则, 刮擦;

    注意形式参数 scratchpad 草稿行 对于其他函数,这些函数不再需要模板技巧,只需使用左值引用参数即可。

    xyz.initialize_computation(scratchpad_t(1, 2, 3)); initialize_computation 完成了,对吗?将引用存储在 xyz 为以后的用户提供对象将是一个非常糟糕的主意。

    自我() 不需要是成员方法,它可以是模板函数

    template <typename T>
    T& as_lvalue(T&& x)
    {
        return x;
    }
    
        2
  •  4
  •   Benjamin Lindley    15 年前

    问题在于:

    scratchpad_t<typeX<typeY,potentially::messy>, typename T> useless_temp = factory(rng_parm);
    

    auto useless_temp = factory(rng_parm);
    
        3
  •  3
  •   Billy ONeal IS4    15 年前

    就我个人而言,我宁愿看到 const_cast mutable . 当我看到 可变的 ,我假设有人在做合乎逻辑的事情 const -是的,别想太多。

    一种选择是使用 shared_ptr ( auto_ptr 取决于什么 factory ,并按值传递它,这样可以避免复制成本,并且只维护一个实例,但是可以从工厂方法传入。

        4
  •  0
  •   David Rodríguez - dribeas    15 年前

    std::auto_ptr<scratch_t> create_scratch();
    
    foo( *create_scratch() );
    

    auto_ptr 而不是堆栈中的对象。他回来了 自动\u ptr temporary将拥有对象的所有权,但是您可以对temporary调用非常量方法,并且可以取消对指针的引用以获得真正的引用。在下一个序列点,智能指针将被销毁,内存将被释放。如果你需要通过同样的考试 scratch_t 对于一行中的不同函数,只需捕获智能指针即可:

    std::auto_ptr<scratch_t> s( create_scratch() );
    foo( *s );
    bar( *s );
    

    std::unique_ptr 在即将发布的标准中。

        5
  •  0
  •   Eamon Nerbonne    15 年前

    template <typename T> T & temp(T && temporary_value) {return temporary_value;}
    

    此函数只是转发普通的左值引用,并将右值引用转换为左值引用。当然,这样做会返回一个可修改的值,该值的结果会被忽略——这恰好是我想要的结果,但在某些上下文中可能会显得很奇怪。