C ++逻辑运算符返回值

时间:2009-09-22 15:54:41

标签: c++

这是我用C ++编写的一些代码。有一个addAVP()函数的调用

dMessage.addAVP(AVP_DESTINATION_HOST, peer->getDestinationHost() || peer->getHost());

有两个版本:第二个参数重载为addAVP(int, char*),另一个重载为addAVP(int, int)。我发现我使用的C ++编译器调用addAVP(int, int)版本,这不是我想要的,因为getDestinationHost()getHost()都返回char*

尽管如此||运算符定义为返回bool所以我可以看到我的错误在哪里。 Bool以某种方式计算为一个整数,这将完全编译并调用第二个addAVP()

最近我使用了很多动态类型的语言,即lisp,上面的代码是正确的,可以毫无后顾之忧地编写。很明显,C ++中的上述代码显然是一个很大的错误,但仍有一些问题:

  1. 我是否应该使用这种快捷方式,即在C ++中使用|| -operator的返回值。这个编译器是否依赖?

  2. 想象一下,我真的非常 编写好的a || b语法,这可以在C ++中干净利落地完成吗?通过编写运算符重定义?不失性能?

  3. 作为我原始请求的后续内容,或者我自己对2的回答:-)我正在考虑使用类来封装(邪恶?)rawpointer:

    class char_ptr_w {
      const char* wrapped_;
    public:
      char_ptr_w(const char* wrapped) : wrapped_(wrapped) {}
      char_ptr_w(char_ptr_w const& orig) {  wrapped_=orig.wrapped(); }
      ~char_ptr_w() {}
      inline const char* wrapped() const { return wrapped_; }
    };
    
    inline char_ptr_w operator||(char_ptr_w &lhs, char_ptr_w& rhs) {
      if (lhs.wrapped() != NULL)
        return char_ptr_w(lhs.wrapped());
      else
        return char_ptr_w(rhs.wrapped());
    };
    

    然后我可以使用:

    char_ptr_w a(getDestinationHost());
    char_ptr_w b(getHost());
    
    addAVP(AVP_DESTINATION_HOST, a || b);
    

    addAVP将为char_ptr_w重载a?b:c。根据我的测试,这最多生成与三元{{1}}解决方案相同的汇编代码,特别是因为运算符中的NRVO优化,而,在大多数编译器中,调用副本-constructor(虽然你包含它)。

    当然,在这个特定的例子中,我同意三元解决方案是最好的。我也同意操作员重新定义是谨慎使用的,并不总是有益的。但是在C ++意义上,使用上述解决方案有什么概念上的错误吗?

6 个答案:

答案 0 :(得分:7)

在C ++中使逻辑运算符重载是合法的,但只有当一个或两个参数属于类类型时,无论如何它都是一个非常糟糕的主意。 重载逻辑运算符不会短路,因此这可能会导致程序中其他位置显然有效的代码崩溃。

return p && p->q;  // this can't possibly dereference a null pointer... can it?

答案 1 :(得分:5)

正如你所发现的,bool实际上是一个int。编译器正在为您的足迹选择正确的函数。如果您想保留类似的语法,可以尝试

char*gdh=0;
dMessage.addAVP(AVP\_DESTINATION\_HOST, 
                (gdh=peer->getDestinationHost()) ? gdh : peer->getHost());

我强烈建议不要重新定义运营商。从维护的角度来看,这很可能会使后来的开发人员感到困惑。

答案 2 :(得分:4)

为什么在两个char指针上使用“or”运算符?

我假设peer-> getDestinationHost()或peer-> getHost()可以返回NULL,并且您正在尝试使用返回有效字符串的那个,对吗?

在这种情况下,您需要单独执行此操作:


char *host = peer->getDestinationHost();
if(host == NULL)
  host = peer->getHost();
dMessage.addAVP(AVP\_DESTINATION\_HOST, host);

将布尔值传递给需要char *的函数是没有意义的。

在C ++中||返回一个bool,而不是它的一个操作数。打击这种语言通常是一个坏主意。

答案 3 :(得分:2)

  

1)我是否应该使用这种快捷方式,即在C ++中使用|| -operator的返回值。这个编译器是否依赖?

它不依赖于编译器,但它与||的作用不同运算符使用JavaScript或or等常见的lisp语言。它将第一个操作数强制转换为布尔值,如果该操作数为true,则返回true。如果第一个操作数为false,则计算第二个操作数并将其强制转换为布尔值,并返回此布尔值。

所以它的作用与( peer->getDestinationHost() != 0 ) || ( peer->getHost() != 0 )相同。此行为不依赖于编译器。

  

2)想象一下,我真的,真的不得不写出好的|| b语法,这可以在C ++中干净利落地完成吗?通过编写运算符重定义?不失性能?

由于你使用指向chars的指针,你不能重载运算符(重载需要一个类类型的正式参数,并且你有两个指针)。等效语句C ++将第一个值存储在一个临时变量中,然后使用?:三元运算符,或者你可以用内联函数来计算第一个表达式两次的成本。

答案 4 :(得分:1)

您可以改为执行以下操作:

dMessage.addAVP(AVP_DESTINATION_HOST,(peer-> getDestinationHost())?peer-> getDestinationHost():peer-> getHost());

这不像||那样整洁但接近它。

答案 5 :(得分:1)

嗯,你的代码问题是对的:a || b将返回一个bool,它被转换为int(0表示false,!= 0表示true)。

关于你的问题:

  1. 我不确定返回值是否实际在标准中定义,但我不会使用||的返回值在除了布尔之外的任何情况下(因为它不会很清楚)。

  2. 我会用的吗?而不是运营商语法是:(表达式)? (如果为true则执行):(如果为false则执行)。所以在你的情况下,我写道:( peer-> getDestinationHost()=!NULL)? peer-> getDestinationHost():peer-> getHost()。当然,这将调用getDestinationHost()两次,这可能是不可取的。如果不是,那么你将不得不保存getDestinationHost()的返回值,在这种情况下,我只是忘记简短而整洁,只需在函数调用之外使用一个普通的旧“if”。这是保持其工作,效率,最重要的是,可读的最佳方式。

相关问题