【问题标题】:Check if only one string variable is not nullptr in C++检查 C++ 中是否只有一个字符串变量不是 nullptr
【发布时间】:2017-08-04 04:18:01
【问题描述】:

我有三个LPCWSTR 字符串变量,分别称为ABC

我从另一个函数分配它们,如果出现问题,有时会返回 nullptr。像这样:

A = MyFunc();
B = MyFunc();
C = MyFunc();

现在,对于一些带有这些变量的东西,我需要检查这些变量中是否只有一个不是nullptr(只分配了一个变量)。

我自己尝试这样做:

if ((A == nullptr) && (B == nullptr) && (C <> nullptr)) {}

欢迎任何关于如何做到这一点的想法。

【问题讨论】:

  • 你不能链接xor,然后否定结果吗?像!(A ^ B ^ C) 这样的东西。 ^ 是按位的,但它可以工作吗?只是吐球。
  • 我们可以假设你不在乎哪一个是空的,只要一个并且只有一个是空的?
  • 除非你想被阅读你代码的其他程序员永远诅咒,否则我会避开像 XOR 这样的“聪明”解决方案 :-) 优化可读性首先!
  • C &lt;&gt; nullptr 不是有效的 C++。你试图表达的可能是C != nullptr
  • 对于只有 3 个变量,最简单的解决方案确实是 (A &amp;&amp; !B &amp;&amp; !C) || (!A &amp;&amp; B &amp;&amp; !C) || (!A &amp;&amp; !B &amp;&amp; C) - 不要陷入抽象! (或!!A + !!B + !!C == 1

标签: c++ variables null nullptr


【解决方案1】:

很容易做到:

int numSet = 0;
A = MyFunc(); if (A != nullptr) numSet++;
B = MyFunc(); if (B != nullptr) numSet++;
C = MyFunc(); if (C != nullptr) numSet++;
if (numSet == 1) // only one is set

您还可以使用辅助函数封装该行为:

LPCWSTR MyFuncWithCount(int &countSetProperly) {
    LPCWSTR retVal = MyFunc();
    if (retVal != nullptr) countSetProperly++;
    return retVal;
}

int numSet = 0;
A = MyFuncWithCount(numSet);
B = MyFuncWithCount(numSet);
C = MyFuncWithCount(numSet);
if (numSet == 1) // only one is set

下一步将使用 基于范围的 for 循环花括号初始化列表,按照以下完整程序:

#include <iostream>
#include <vector>

typedef void * LPCWSTR;  // Couldn't be bothered including Windows stuff :-)

int main() {
    // Only set two for test purposes.

    LPCWSTR A = nullptr, B = nullptr, C = nullptr;
    LPCWSTR D = &A,      E = nullptr, F = &A;

    int numSet = 0;
    for (const auto &pointer: {A, B, C, D, E, F})
        if (pointer != nullptr)
            numSet++;

    std::cout << "Count is " << numSet << std::endl;
}

或者您可以通过使用 lambda 函数来拥抱现代 C++ 的所有荣耀,如下所示:

#include <iostream>
#include <vector>

typedef void * LPCWSTR;  // Couldn't be bothered including Windows stuff :-)

int main() {
    // Only set two for test purposes.

    LPCWSTR A = nullptr, B = nullptr, C = nullptr;
    LPCWSTR D = &A,      E = nullptr, F = &A;

    int numSet = 0;
    [&numSet](const std::vector<LPCWSTR> &pointers) {
        for (const auto &pointer: pointers)
            if (pointer != nullptr)
                numSet++;
    } (std::vector<LPCWSTR>{A,B,C,D,E,F});

    std::cout << "Count is " << numSet << std::endl;
}

对于您的特定情况,这可能有点矫枉过正:-)

【讨论】:

  • 谢谢!这醒来很好。但是,我也会看一下 XOR。 :-)
  • 您不能使用std::initializer_list 而不是std::vector 来避免分配。那和...std::count.
  • 我以前从未在 C++ 中看到过立即调用的 lambda 表达式...为什么不直接使用 for (const auto&amp; pointer : {A, B, C, D, E, F}) { ...
  • 你的编码风格……令人沮丧。
  • @Tavian 等人,这并不是一个真正的严肃建议,我只是从基础到超级高级。但是,我可能只是将您的建议放在辅助函数和荒谬的 lambda 之间:-)
【解决方案2】:

使用 std,您可以这样做:

const auto vars = {A, B, C}; // Create initializer list.
const bool onlyOneNotNull =
    (std::count(vars.begin(), vars.end(), nullptr) == (vars.size() - 1);
// then you may use find_if to retrieve the non null variable.

【讨论】:

    【解决方案3】:

    这是一种简单的方法:

    int not_null = 0;
    not_null += A != nullptr;
    not_null += B != nullptr;
    not_null += C != nullptr;
    if (not_null == 1) {
        /* Do stuff */
    }
    

    检查每个是否为nullptr,如果不是则增加一个计数。如果计数最终显示为1,请执行您的操作。

    【讨论】:

      【解决方案4】:

      在 C++ 中,为了与 C 向后兼容,关系运算符的返回值为 int 等于 01。所以你可以这样做:

      if ( (a != nullptr) + (b != nullptr) + (c != nullptr) == 1 )
      

      如果你只想将逻辑运算符用作逻辑运算符,那么还有析取范式和合取范式,尽管操作更多。

      if ( (a && !b && !c) || (!a && b && !c) || (!a && !b && c) )
      

       

      if ( (a || b || c) && (!a || !b) && (!a || !c) && (!b || !c) )
      

      与大多数其他解决方案相比,在这种简单的情况下,前者并不难阅读,尽管如果有更多可能的解决方案,它很快就会变得过于冗长。

      您也可以将它们粘贴在任何容器中,例如 std::array&lt;LPCWSTR, 3&gt;,然后使用 std::count( pointers.begin(), pointers.end(), nullptr)(如 Jarod42 建议的那样)。

      【讨论】:

        【解决方案5】:

        我一般不太喜欢使用以下技术,但您可以使用这样一个事实,即对于任何指针 ptr!!ptr 对于空指针的计算结果为 0,对于非空指针计算结果为 1写指针

        if (!!A + !!B + !!C == 1) {
            ...
        }
        

        作为实现此功能的一种密集方式。它与@Davislor 的解决方案基本相同,但具有更紧凑的“test if null”检查。

        这种方法的扩展性几乎不如公认的方法,而且阅读起来也比较棘手,但取决于您的受众和阅读代码的人,它可能会很好地完成这项工作。

        【讨论】:

        • 如果这是 Code Golf,你会赢的!我不认为我真的会这样写,但它很聪明。
        猜你喜欢
        • 2017-06-06
        • 2018-05-23
        • 1970-01-01
        • 1970-01-01
        • 2011-05-02
        • 2011-12-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多