微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

当C ++函数不“移出”右值引用参数时,这是否合理?

如何解决当C ++函数不“移出”右值引用参数时,这是否合理?

假设class Object满足 MoveConstructible MoveAssignable 的要求,但不满足 copyConstructible 的要求copyAssignable (即其中包含unique_ptr的PIMPL)。然后,我有两个消费者:

 bool consumer1(Object && arg) {
       if(arg ...) { // arg satisfies some condition
          Object b {std::move(arg)};
          // some processing
          return true;
        }
        return false;
 }

 bool consumer2(Object &&arg) {};

 int main() {
     Object arg;
     // some arg initialization here
     if(!consumer1(std::move(arg))) 
        consumer2(std::move(arg));
 }

即我想移动一个Object实例到consumer1(),如果由于某种原因它不接受它,我将该实例移到consumer2()。

或者,我可以检查实例的状态(即是否从实例中移出),而不用依赖返回值。

我知道that

std :: move不会移动任何东西。

尽管如此,由于两次举动,我感到不舒服。

这是一种合理的方法吗?是否有较简单的方法来实现相同的想法?

解决方法

这个问题是很主观的,但是我会尽力回答。

虽然您编写的代码在技术上没有任何错误,但由于该代码可以正确编译并正常运行,因此从更高层次上讲这是一种设计气味。

对对象std::move的明显重复调用限制了开发人员推断该对象寿命的能力,这可能会降低可读性。静态分析工具也可以将这种移动标记为“移动后使用”,尽管实际上该对象尚未真正就位(从技术上讲这不会错)。

我想到了几个清理选项,但是它们是完全可选的,并且取决于您的实际用例:

  1. std::move的条件分解为单独的支票,或者
  2. 使用后备模式

打破条件

如果您可以打破consumer1消费arg的条件,则可以在首次尝试消费之前进行显式测试-允许您拥有两个明显不同的分支到{{1 }}独立地:

std::move(arg)

后退模式

另一种可能的重构方式是使用回退模式,在该模式中,您设计代码时会在失败时发生依赖项注入的“回退”。

如果这只是简单的原始函数,那么简单的例子可能是:

if(can_consume(arg)) {
    consumer1(std::move(arg));
} else {
    consumer2(std::move(arg));
} 

但是,这也可以扩展到完整接口,其中扩展了using FallbackFunction = void(*)(Object&&); void consume1_or(Object&& arg,FallbackFunction function) { if(arg ...) { // arg satisfies some condition Object b {std::move(arg)}; // some processing return } // fallback on failure (*function)(std::move(arg)); } ... // use consume1_or(std::move(arg),&consume2); 的对象在构造时也接受Consumer以便在失败时将对象传递给对象。

,

正如您所编写的,当1返回false时,arg仍处于有效状态,因此您的代码没有任何错误(即使不是,也仍然存在)没错)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。