我有一个C ++数据结构,这是其他计算所需的“ scratchpad”。它不是长寿的,也不经常使用,因此性能也不关键。但是,它在其他可更新的跟踪字段中包括一个随机数生成器,尽管生成器的实际值并不重要,但它 重要的是要更新值而不是复制和重复使用。 这意味着通常,该类的对象是通过引用传递的。

如果仅需要一次实例,则最自然的方法是在需要的任何地方构造它们(也许是使用工厂方法或构造函数),然后将Scratchpad传递到消费方法。消费者的方法签名使用通过引用使用,因为他们不知道这是唯一的用途,但是出厂方法和构造函数按值返回 - 您不能通过参考来传递未命名的临时性。

有没有办法避免用讨厌的临时变量堵塞代码?我想避免以下内容:

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个功能就足够了。

编辑: 明确地说,使用临时性是可行的,这只是我想避免的代码中不幸的混乱。如果您从不给临时名称命名,那么它显然只使用了一次,并且读取的代码行越少,越好。同样,在构造师的初始化器中,不可能宣布临时工。

有帮助吗?

解决方案

虽然将rvalues传递给接受非const引用的函数是不行的,但是可以在rvalues上调用成员函数,但是成员函数不知道如何调用。如果您返回对当前对象的引用,则可以将RVALUES转换为LVALUE:

class scratchpad_t
{
    // ...

public:

    scratchpad_t& self()
    {
        return *this;
    }
};

void foo(scratchpad_t& r)
{
}

int main()
{
    foo(scratchpad_t().self());
}

注意如何呼吁 self() 即使 scratchpad_t 是一个rvalue。

如果我错了,请纠正我,但是RVALUE参考参数不接受LVALUE参考,因此使用它们需要向所有ScratchPad的消费者添加过载,这也很不幸。

好吧,您可以使用模板...

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

如果您打电话 foo 使用RVALUE参数, Scratch 将被推论 scratchpad_t, , 因此 Scratch&& 将会 scratchpad_t&&.

如果你打电话 foo 使用LVALUE参数, Scratch 将被推论 scratchpad_t&, ,并且由于参考折叠规则, Scratch&& 也将是 scratchpad_t&.

请注意,正式参数 scratchpad 是名称,因此是LVALUE,无论其类型是LVALUE参考还是RVALUE参考。如果你想通过 scratchpad 在其他功能上,您不再需要这些功能的模板技巧,只需使用lvalue参考参数即可。

顺便说一句,您确实意识到涉及的临时刮擦 xyz.initialize_computation(scratchpad_t(1, 2, 3)); 将立即被销毁 initialize_computation 完成了,对吗?在内部存储参考 xyz 以后用户的对象将是一个极其糟糕的主意。

self() 不需要是会员方法,它可以是模板功能

是的,这也是可能的,尽管我会重命名以使意图更清晰:

template <typename T>
T& as_lvalue(T&& x)
{
    return x;
}

其他提示

问题就是这样:

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

丑陋吗?如果是这样,那为什么不将其更改为呢?

auto useless_temp = factory(rng_parm);

就个人而言,我宁愿看到 const_castmutable. 。当我看见 mutable, ,我假设有人在做逻辑 const- 不考虑太多。 const_cast 但是,将危险信号升起,因为这样的代码应该。

一种选择是使用类似的东西 shared_ptr (auto_ptr 会根据什么来工作 factory 正在执行)并按值传递,这避免了复制成本并仅维护一个实例,但可以从您的工厂方法传递。

如果您在堆中分配对象,则可以将代码转换为类似的内容:

std::auto_ptr<scratch_t> create_scratch();

foo( *create_scratch() );

工厂创建并返回 auto_ptr 而不是堆栈中的对象。返回 auto_ptr 临时性将占据对象的所有权,但是您可以暂时调用非const方法,您可以取消指针以获取真实参考。在下一个序列点,智能指针将被破坏并释放。如果您需要通过相同 scratch_t 对于一排不同的功能,您可以捕获智能指针:

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

可以替换 std::unique_ptr 在即将到来的标准中。

我将Fredoverflow的回答标记为他的建议,以使用一种方法来简单地返回非const参考。这在C ++ 03中起作用。该解决方案需要类似于SCRATCHPAD类型的成员方法,但是在C ++ 0x中,我们还可以更一般地为任何类型编写该方法:

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

此函数只是转发正常的LVALUE参考,然后将RVALUE引用转换为LVALUE参考。当然,这样做会返回一个可修改的值,其结果被忽略了 - 这恰好是我想要的,但在某些情况下似乎很奇怪。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top