Есть ли хороший способ убедиться, что результат функции C ++ не игнорируется? - PullRequest
7 голосов
/ 22 июня 2011

Недавно я столкнулся с случаем, когда у меня была постоянная функция-член, выполняющая операцию и возвращающая результат.Например,

class Foo { ...
    Foo add(Foo const & x) const;
}

Но кто-то другой случайно вызвал его, как будто он обновлял объект this (игнорируя результат):

Foo a = ...;
Foo b = ...;
a.add(b);

(Эта ошибка была фактически введенанесовершенный рефакторинг.)

Есть ли способ заставить последнюю строку выше вызвать ошибку или предупреждение?Следующей лучшей вещью будет улов во время выполнения, который в основном решается с помощью следующего шаблона.Однако это убивает оптимизацию возвращаемого значения, что видно по результату счетчика.

template<typename T>
class MustTake {
    T & obj;
    bool took;
public:
    MustTake(T o) : obj(o), took(false) {}
    ~MustTake() { if (!took) throw "not taken"; }
    operator T&() { took = true; return obj;}
};

struct Counter {
    int n;
    Counter() : n(0) {}
    Counter(Counter const & c) : n(c.n+1) {}
    ~Counter() {}
};

Counter zero1() {
    return Counter();
}

MustTake<Counter> zero2() {
    return Counter();
}

int main() {
    Counter c1 = zero1();
    printf("%d\n",c1.n);    // prints 0
    Counter c2 = zero2();
    printf("%d\n",c2.n);    // prints 1
    zero1();    // result ignored
    zero2();    // throws
    return 0;
}

Полагаю, я могу уменьшить неэффективность с помощью макроса, чтобы MustTake <> был только для отладки и не работал длявыпуск.

Я ищу решение во время компиляции.В противном случае я ищу лучшее решение во время выполнения.

Ответы [ 3 ]

8 голосов
/ 22 июня 2011

Это то, что атрибуты функции для ( документация ) в GCC и Clang, но это не переносимо, например, MSVC.

class Foo { ...
    __attribute__((warn_unused_result))
    Foo add(Foo const & x) const;
}

В документации говорится, что он используется на realloc , например, , но не отображается ни в каких других стандартных функциях моей системы.

Вас также может заинтересовать использование статического анализатора Clang, который отслеживает поток данных по вызовам функций и может выдавать вам более точные предупреждения.

7 голосов
/ 22 июня 2011

Для Microsoft VC ++ есть аннотация _Check_return_: http://msdn.microsoft.com/en-us/library/ms235402(v=VS.100).aspx

0 голосов
/ 13 апреля 2017

Если важно, чтобы возвращаемое значение не игнорировалось вызывающей функцией, шаблон dont_ignore можно использовать следующим образом

ДО:

int add( int x, int y )
{
    return x + y;
}

ПОСЛЕ:

dont_ignore<int> add( int x, int y )
{
    return x + y;
}

Если вызывающая функция не использует возвращаемое значение, генерируется исключение.Определение dont_ignore:

template<class T>
struct dont_ignore
{
    const T     v;
    bool        used;

    dont_ignore( const T& v )
        :  v( v ), used( false )
    {}

    ~dont_ignore()
    {
        if ( !used )
            throw std::runtime_error( "return value not used" );
    }

    operator T()
    {
        used = true;
        return v;
    }
};
...