c++ 为什么不把[[nodiscard]]应用到每个构造函数呢?

nx7onnlm  于 2022-11-27  发布在  其他
关注(0)|答案(2)|浏览(146)

从C++20开始,[[nodiscard]]就可以应用于构造函数。http://wg21.link/p1771的例子如下:

struct [[nodiscard]] my_scopeguard { /* ... */ };
struct my_unique {
  my_unique() = default;                                // does not acquire resource
  [[nodiscard]] my_unique(int fd) { /* ... */ }         // acquires resource
  ~my_unique() noexcept { /* ... */ }                   // releases resource, if any
  /* ... */
};
struct [[nodiscard]] error_info { /* ... */ };
error_info enable_missile_safety_mode();
void launch_missiles();
void test_missiles() {
  my_scopeguard();              // warning encouraged
  (void)my_scopeguard(),        // warning not encouraged, cast to void
    launch_missiles();          // comma operator, statement continues
  my_unique(42);                // warning encouraged
  my_unique();                  // warning not encouraged
  enable_missile_safety_mode(); // warning encouraged
  launch_missiles();
}
error_info &foo();
void f() { foo(); }             // warning not encouraged: not a nodiscard call, because neither
                                // the (reference) return type nor the function is declared nodiscard

通常构造函数没有副作用。因此丢弃结果是没有意义的。例如,如下所示丢弃std::vector是没有意义的:

std::vector{1,0,1,0,1,1,0,0};

如果std::vector构造函数为[[nodiscard]],则会很有用,因此上面的代码会产生一个警告。
有副作用的构造函数是锁构造函数,如unique_locklock_guard。但这些构造函数也是标记为[[nodiscard]]的好对象,以避免丢失作用域,如下所示:

std::lock_guard{Mutex};
InterThreadVariable = value; // ouch, not protected by mutex

如果std::lock_guard构造函数为[[nodiscard]],则会很有用,因此上面的代码会产生一个警告。
当然,也有像return std::lock_guard{Mutex}, InterThreadVariable;这样的情况,但是仍然有[[nodiscard]]保护并像return ((void)std::lock_guard{Mutex}, InterThreadVariable);那样在本地抑制它们的情况非常罕见
那么,有没有什么情况下构造函数 * 不 * 应该是nodiscard?

cygmwpex

cygmwpex1#

pybind11库中的示例:要为python Package 一个C++类,您需要:

PYBIND11_MODULE(example, m) {
    py::class_<MyClass>(m, "MyClass");  // <-- discarded.
}
qaxu7uf2

qaxu7uf22#

如果构造函数没有副作用,那么在我看来就不值得这么做,代码也很混乱。您很快就会注意到,在示例中您忘记了为该向量命名。
对于少数有副作用的构造函数,现在有[[nodiscard]]可用。(这很好)
因为你的问题是为什么不改变默认值并用[[may_discard]]标记例外情况(基本上C的定义似乎到处都是错误的默认值),这将是向后兼容性。这样的中断通常只在极少数情况下被接受,即现有的东西是有害的,并且如果有替代品的话。(想到了std::auto_ptr的反对意见)
现在有一些新的方法来解决这个问题。一个例子是Herb Sutter的个人实验cppfront。它定义了一种新的语法,可以正确地获取所有默认值,并将其转换为常规的C
,然后进行编译。你可以查看他在CppCon 2022的主题演讲,他在演讲中演示了这一点:Can C++ be 10x Simpler & Safer?

相关问题