Можно ли создать объект класса только для lvalue? - PullRequest
0 голосов
/ 29 декабря 2018

Хорошо известная проблема с std::lock_guard (и его родственниками) заключается в том, что он работает не так, как ожидалось, когда создается только временный объект.

Например:

std::mutex mtx;

std::lock_guard<std::mutex> {mtx} // temporary object, does not lock the entire scope

std::lock_guard<std::mutex> lck{mtx} // correct

Я попробовал ссылочные квалификаторы, чтобы создать замену, которая препятствует созданию временного объекта (во время компиляции).Следующий код - тщетная попытка:

#include <mutex>

template<typename T>
struct my_lock {
    T &mtx;
    my_lock(T &t) : mtx{t} { lock(); }
    ~my_lock() { unlock(); }

    void lock() & { mtx.lock(); };
    void unlock() & { mtx.unlock(); };
};


std::mutex mtx;

int main()
{
    my_lock<std::mutex> {mtx}; // A 

    my_lock<std::mutex lck{mtx}; // B
}

Это не работает, поэтому возникает вопрос:

Можно ли написать класс таким образом, чтобы компилятор отклонил A и принимает B?

Ответы [ 2 ]

0 голосов
/ 29 декабря 2018

Позвольте мне переосмыслить ваш вопрос вместо:

Возможно ли написать класс таким образом, чтобы компилятор отклонил A и принял B?

Я собираюсь прочитать это как

Возможно ли, чтобы мой компилятор отклонил A и принял B?

Да, это возможно в зависимости от компилятора без необходимостинаписать свои собственные классы.Я хорошо знаком с clang, однако подобные проверки будут существовать в других компиляторах или статических анализаторах.

Для clang -Wunused-value -Werror выполнит эту работу.Первый активирует предупреждение, второй выводит его на ошибку.

Лично я за то, чтобы я включил все предупреждения и явно отключил те, к которым у вас есть основания не соблюдать, включая документацию о причинах.

0 голосов
/ 29 декабря 2018

если вы можете использовать c++17, вы можете использовать атрибут [[nodiscard]] с заводской функцией.


class [[nodiscard]] my_lock{
   my_lock()=default;
   friend my_lock lock();
};
[[nodiscard]] my_lock lock(){return {};}

int main(){
    { lock(); } //warning for discard return value
    { auto l = lock();}
}
...