0

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(这对于异常类型非常有用!) - 并且字符串也在调用站点“验证”。

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

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

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

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

4

1 回答 1

3

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

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使您的异常类容易被滥用。存储 aconst char*也会有同样的问题。

std::string_view(and 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为你做的事情。

于 2019-10-18T12:49:46.097 回答