为什么没有可以为int或false的数据类型?

时间:2017-09-16 13:01:44

标签: c++

我是学习c ++。我看到你通常使用整数来存储一个值,如果我们想表示没有值,那么我们使用-1。例如,在不包含字符串的向量中搜索字符串索引的返回值为-1。在Javascript中很容易:你只是声明它是假的。 我经常遇到两个问题:

  • 如果我只打算使用正值,那么我就浪费了为int分配的所有可用范围。所有数字从-2到-32768
  • 如果我打算使用负值,这种方法就没用了。

我知道javascript是一个不同的世界,但是,例如,这种数据类型的范围在C ++中可以是-1到65534。那么为什么C ++的数据类型不能是数字还是假?还是有一个我忽略的共同编程技巧?

2 个答案:

答案 0 :(得分:3)

C ++ 17 中有一个可选类型,名为std :: optional。

但我认为你错过了一件事。 C ++一方面是一种非常现代的编程语言,它提供了许多其他现代语言提供的思​​想。另一方面,它的设计考虑了效率,内存占用效率和速度效率。

  

例如,从一个字符串中搜索字符串的索引返回   不包含该字符串的向量将为-1。在Javascript中   容易:你只是声明它是假的。我经常遇到两个问题:   如果我打算只使用正值,我会浪费所有可用的   为int分配的范围。所有数字从-2到-32768

那说:

  • 当找不到索引时,std :: vector find返回end()而不是-1。
  • std :: basic_string :: find不会返回int值,而是size_t,这实际上是无符号的。是,-1是使用的文字,但对于无符号类型-1是最大可表示值。除了正好一个值,即最大值,你不会丢失任何东西。 -1 one是表示size_t最大值的最方便的便携方式。

在许多实现中,size_t的最大值是18446744073709551615,并且大多数c ++开发人员更喜欢无法搜索长度超过18446744073709551614的字符串(这无论如何都很现实)来摆弄有效可选类型的问题或为标志花费额外的字节

即使size_t最大为65535,65534的大小不足但65535的概率非常接近于零。

答案 1 :(得分:0)

首先,C ++中的函数返回类型是在编译时定义的,这就是为什么你不能做这样的事情

// ...
if (found)
    return index;
else
    return false;

有几种方法可以解决这个问题。您必须根据您的申请选择。第一个要考虑的是与STL库一致的。容器为其元素提供迭代器,find返回所请求元素的迭代器。如果未找到,则返回迭代器到容器的past-the-end元素。例如,可以写

// on some container that offers the standard interface
auto it = container.find(value);
if (it == container.end()) {
    // not found
}

以上是最干净的解决方案。这就是std::vector和STL中的每个其他容器发出未找到值的信号。编写这样的代码的主要好处是,您可以将容器替换为任何其他容器,代码仍然有效。或者,如果您使用兼容接口设计自己的容器,则可以无缝地将其插入现有代码中。

然而,在其他情况下,这可能不起作用。例如,您可能只需要实际索引,并且可能很难从非连续容器上的迭代器获取。在这种情况下,您可以使用std::optional。它要么拥有一个对象,要么为空,并提供bool转换以便于检查。

std::optional<int> my_find(T value) {
// ...
    if (found) // pseudo-condition, depends on the rest of the code
        return std::optional<int>(index); // explicit, could be more compact
    else
        return std::optional<int>();      // default optional is empty
}

// elsewhere
auto i = my_find();
if (!i) {
    // not found
}

注意上面的内容,会增加空间开销以跟踪对象是否存在。如果由于任何原因这是不可接受的,你可以采用sentinel值的想法,并创建一个紧凑的可选对象,其中sentinel值在内部用于表示不存在值,并提供一个接口来检查它,也许是一个例外如果用户在对象为空时请求值,则抛出。像

这样的东西
template <typename T, T sentinel_value>
class CompactOptional {
private:
    T value;

public:
    CompactOptional(value = sentinel_value): value(value) {}

    operator bool () { return value != sentinel_value; }

    // getter and setter according to your needs
}

你必须决定当你试图获得一个不存在的值时会发生什么,然后就是这样。标记值是您不能使用的任何值,如果使用unsigned,则可能是整数类型的最大值。