Since C++20, [[nodiscard]]
can be applied to constructors. http://wg21.link/p1771 has the example:
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
Usually constructors have no side effects. So discarding the result is pointless. For example, discarding std::vector
as below is pointless:
std::vector{1,0,1,0,1,1,0,0};
It would be useful if std::vector
constructor is [[nodiscard]]
, so that the above code produced a warning.
Notable constructors that do have side effects are lock constructors, like unique_lock
or lock_guard
. But then those are good target to be marked as [[nodiscard]]
as well, to avoid missed scope, like here:
std::lock_guard{Mutex};
InterThreadVariable = value; // ouch, not protected by mutex
It would be useful if std::lock_guard
constructor is [[nodiscard]]
, so that the above code produced a warning.
Sure there's a case like return std::lock_guard{Mutex}, InterThreadVariable;
. But it is rare enough to still have [[nodiscard]]
guards, and to suppress them locally like return ((void)std::lock_guard{Mutex}, InterThreadVariable);
So, is there any case when a constructor should not be nodiscard?
An example from the pybind11
library: To wrap a C++-class for python, you do:
PYBIND11_MODULE(example, m) {
py::class_<MyClass>(m, "MyClass"); // <-- discarded.
}