繁体   English   中英

C ++逻辑运算符返回值

[英]C++ logical operators return value

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

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

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

尽管如此|| 运算符定义为返回布尔值,因此我可以看到我的错误在哪里。 布尔以某种方式计为整数,并且可以干净地编译并调用第二个addAVP()

最近,我使用了许多动态类型化的语言,即lisp,上面的代码是正确的,可以编写而无需担心。 显然,上面的C ++代码显然是一个大错误,但仍然存在一些问题:

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

  2. 想象一下,我真的不得不写一个漂亮a || b a || b语法,可以在C ++中干净地完成吗? 通过编写运算符重新定义? 不损失性能?

作为我最初的请求的后续行动,或者是我自己对2 :-)的回答,我一直在考虑使用类来封装(邪恶的)原始指针:

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的解决方案,特别是因为NRVO优化操作,这 ,在大多数编译器,调用拷贝构造函数(尽管你包括在内)。

自然,在这个特定示例中,我同意三元解决方案是最好的。 我也同意,重新定义操作员是要小心的事情,并不总是有益的。 但是,从C ++的角度来看,上述解决方案在概念上有什么问题吗?

重载逻辑运算符在C ++中是合法的,但前提是一个或两个参数均为类类型,无论如何这是一个非常糟糕的主意。 重载的逻辑运算符不会短路 ,因此这可能导致程序中其他地方的有效代码明显崩溃。

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

如您所见,布尔确实是一个整数。 编译器正在为您的占用空间选择正确的功能。 如果您想保留相似的语法,可以尝试

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

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

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

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

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


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

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

在C ++中|| 返回布尔值,而不是其操作数之一。 与语言作斗争通常是个坏主意。

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

它与编译器无关,但与||的功能不同 运算符使用JavaScript等语言or通用Lisp。 它将第一个操作数强制为布尔值,如果该操作数为true,则返回true。 如果第一个操作数为false,则对第二个操作数求值并强制为布尔值,然后返回此布尔值。

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

2)想象一下,我真的必须写一个漂亮的||。 b语法,可以在C ++中干净地完成吗? 通过编写运算符重新定义? 不损失性能?

由于您使用的是指向chars的指针,因此您不能重载运算符(重载需要一个类类型的形式参数,并且您有两个指针)。 等效的C ++语句将第一个值存储在一个临时变量中,然后使用?:三元运算符,或者您可以内联地编写它,但要使用两次评估第一个表达式的代价。

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

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

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

好吧,您对代码的问题所在是正确的: b将返回一个布尔值,该布尔值将转换为int(对于false,为0,对于true为!= 0)。

至于您的问题:

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

  2. 我会用? 运算符。 语法为:(表达式)? (如果为true,则执行):(如果为false,则执行)。 所以在您的情况下,我会写:(peer-> getDestinationHost()=!NULL)吗? peer-> getDestinationHost():peer-> getHost()。 当然,这将两次调用getDestinationHost(),这可能不是所希望的。 如果不是这样,您将必须保存getDestinationHost()的返回值,在这种情况下,我会忘记使其简短而整洁,而在函数调用之外仅使用普通的旧“ if”即可。 这是使它保持工作状态,高效且最重要的是可读性的最佳方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM