一个函数返回了一个值,调用者并没有去接收它,这种代码在C++中并不少见,但某些情况下,返回值是必须要处理的,最简单的例子:
char* getNewMessage() {
char* nm = new char[100];
strcpy(nm, "Hello world");
return nm;
}
int main() {
getNewMessage();
return 0;
}
显然,内存泄露了。
以前这种情况只能靠程序员自己去注意,C++17引入了[[nodiscard]],来告诉调用者,其返回值必须被处理!否则编译器会产生一个warnning,还可以在后面加上一个字符串,说明为什么要处理这个返回值。
[[nodiscard("Release the memory")]]
char* getNewMessage() {
char* nm = new char[100];
strcpy(nm, "Hello world");
return nm;
}
int main() {
getNewMessage();
return 0;
}
这种场景有很多,还有一个例子是unique_lock。
类内的std::mutex一般用于锁类内变量,在成员函数中对其进行unqiue_lock加锁,但有些时候我们需要在类外对加锁成员变量进行操作,这个时候,就要求提供一个成员函数,来单独实现加锁的功能:
class Test {
public:
auto lock() -> std::unique_lock<std::mutex> {
return std::unique_lock<std::mutex>(m_mutex);
}
int &get_data(int &d) {
return data_to_deal_outof_class_;
}
private:
std::mutex m_mutex;
int data_to_deal_outof_class_;
}
int main() {
Test t;
{
t.lock();
int &d = t.get_data();
}
return 0;
}
这显然是有问题的,引起局部变量返回后就析构了,所以锁根本没加上,究其原因就是因为调用者忘记了接收lock()的返回结果,这种情况也是nodiscard的应用场景之一。
这里再解释下锁的使用,首先std::mutex是不允许拷贝也不允许移动的,所以不能写出getMutex()这种接口,unique_lock不允许拷贝,但允许移动,所以有:
std::mutex mutex_;
std::unique_lock ul(mutex_);
std::unique_lock ul2 = ul;//错误
std::unique_lock ul3 = std::move(ul);//正确
这里由于是函数返回值,是自动被判定为右值的,所以优先匹配移动构造,没有问题。(优先复制构造的,没有复制构造函数会报错,优先移动构造的,没有移动构造会继续找复制构造,都没有才会报错)