【问题标题】:null-terminated string_view wanted需要以空结尾的 string_view
【发布时间】:2020-02-15 10:59:56
【问题描述】:

在以下场景中使用std::string_view

struct A : public std::exception{
    A (const char* c) : v_(c){}
    const char* what() const noexcept override;

private:
    std::string_view v_;
};

上面的想法很好用,现在copy-ctor默认为noexcept(这对于异常类型来说非常棒!)-并且字符串也在调用站点“验证”。

然而,剩下的事情是语义上 string_view 不保证为零终止(尽管在这种情况下,我们编写了这样的代码 - 最好是为这种特殊情况保证就像它只有我们实际使用的构造函数一样。

我正在考虑以下类似的方法是否是一个好的解决方法?

struct c_string_view {
  c_string_view(const char* c) : sv_{c}{};
  const std::string_view sv_;
};

但我想知道其他人是否有这个问题(以及他们做了什么),或者我是否忽略了一些简单的东西?

【问题讨论】:

  • 您是否有理由不存储const char* 而不是std::string_view
  • std::exception::what() noexcept 不是virtual 方法,所以你不能override 它。必须是 const 才能成为 override-able。
  • 就我个人而言,我只需要存储一个 std::string。与抛出的成本相比,分配的成本不会被注意到。如果你没有记忆,你有更大的事情要担心。这样做的好处是不必担心传递给异常的事物的生命周期。如果您真的担心能够分配字符串,您可以拥有一个静态成员并预先保留空间并使用它,这样您就不会在异常期间进行分配。
  • 恕我直言,在 excpetion 中使用 std::string_view 本质上是有缺陷的设计,您应该使用好的 'ol std::string
  • 真的,除非您使用 all 内存,否则我不会担心。一根弦很小。根据您的消息是什么,您甚至不会接近使用 KB 空间。你可以在一个 KB 的空间中得到很多单词,而你没有 KB 的空间的可能性几乎为零。

标签: c++ c++17 noexcept string-view


【解决方案1】:

我正在考虑以下类似的方法是否是一个好的解决方法?

const 成员通常是有问题的。它们防止可分配性,并且它们防止移动构造。也就是说,异常类型可能并不总是需要可分配性,并且所讨论的类很快并且无论如何都不需要复制。

因此,在这种情况下,缺点可能不那么明显,但优点也不是那么明显。你的类在构造函数中已经有了空终止的前置条件,并且访问被封装到A的成员函数(和朋友)。


然而,更根本的是,您的异常类很容易被误用。考虑以下典型场景:

throw A(some_local_string.c_str());

char local_buffer[N];
// fill local_buffer with formatted message
throw A(local_buffer);

这些会导致未定义的行为。

为什么它比例如更容易被滥用。 std::string_view

事实上,std::string_view 的使用使您的异常类容易被误用。存储 const char* 也会有同样的问题。

std::string_view(和const char*)适用于函数参数,例如,当函数存储视图的时间超过函数调用者存在的时间时。但是异常几乎是单独使用的,因此它们的寿命比调用者长,因为它们几乎总是被抛出,这会使调用者放松。

如果我/我们从一开始就有 c_string_view - 我们也可以在构造函数中使用它而不是 const char* 来显示意图。

接受c_string_view 并不能真正解决问题,因为它本身并不意味着它将比const char* 存储更多。您可以做的最好的事情是记录如何使用该类,当这些使用排除了常见的异常使用模式时,这有点令人不满意。

也许如果你将类命名为 static_string_exception 或类似名称以使限制更加明显。


来自评论者:

我只需要存储一个 std::string ...

.. 你应该使用好的 'ol std::string

std::string 也不是一个理想的解决方案。它将防止复制构造函数/赋值不抛出(严格来说,但其他选择是程序终止),这对异常类型不利。例如,标准异常类型不允许有抛出的复制构造函数/赋值。

一旦您到达复制路线,您不妨使用std::runtime_error,它会为您做到这一点。

【讨论】:

  • 关于成员常量的好点。关于误用:为什么这比例如更容易误用。 std::string_view - 这实际上是你在那里提出的一个重要观点,我猜这个问题并不清楚(对不起) - 如果我/我们从一开始就有 c_string_view - 我们可以在构造函数中使用它而不是 const char * 也显示意图。
  • @darune string_view 具有相同的误用能力。由于它不拥有调用者需要知道的数据,并确保他们不会向其传递临时数据。
  • 我发现 std::shared_ptr<:string> 有 noexcept 副本,可以作为一个简单的无脑解决方案
  • 我一开始就试过了。我意识到可能的问题可能不太好 - 我从使用 const char* 作为错误类型(一个 typedef,它的工作量太大来替换 atm。)转换,这可能是从函数返回的,初始化为零,等等 - 并抛出
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-17
  • 1970-01-01
  • 1970-01-01
  • 2013-08-10
  • 1970-01-01
  • 1970-01-01
  • 2020-03-18
相关资源
最近更新 更多