Предотвращение предупреждений неиспользуемых переменных при использовании утверждает () в Сборке конечных версий

func screenShotMethod()->UIImage
{
  let layer = self.imageScrollView.layer
  let scale = UIScreen.main.scale
  UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);

  layer.render(in: UIGraphicsGetCurrentContext()!)
  let screenshot = UIGraphicsGetImageFromCurrentImageContext()
  UIGraphicsEndImageContext()

  return screenshot!
}
55
задан R. Martinho Fernandes 17 July 2009 в 04:43
поделиться

9 ответов

We use a macro to specifically indicate when something is unused:

#define _unused(x) ((void)(x))

Then in your example, you'd have:

int Result = Func();
assert( Result == 1 );
_unused( Result ); // make production build happy

That way (a) the production build succeeds, and (b) it is obvious in the code that the variable is unused by design, not that it's just been forgotten about. This is especially helpful when parameters to a function are not used.

51
ответ дан 7 November 2019 в 07:15
поделиться

Я бы использовал следующее:

#ifdef _DEBUG
#define ASSERT(FUNC, CHECK) assert(FUNC == CHECK)
#else
#define ASSERT(FUNC, CHECK)
#endif

...

ASSERT(Func(), 1);

Таким образом, для сборки релиза компилятору даже не нужно создавать какой-либо код для assert.

0
ответ дан 7 November 2019 в 07:15
поделиться
int Result = Func();
assert( Result == 1 );
Result;

This will make the compiler stop complaining about Result not being used.

But you should think about using a version of assert that does something useful at run-time, like log descriptive errors to a file that can be retrieved from the production environment.

0
ответ дан 7 November 2019 в 07:15
поделиться

Вы должны переместить утверждение внутри функции перед возвращаемым значением (ями). Вы знаете, что возвращаемое значение не является локальной переменной, на которую нет ссылок.

Кроме того, в любом случае более разумно находиться внутри функции, поскольку она создает автономный модуль, имеющий свои СОБСТВЕННЫЕ пред- и постусловия.

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

Редактировать, но в этом случае условие публикации должно быть X (см. Комментарии):

Я категорически не согласен с этим, нужно уметь определять условие post из входных параметров и, если это функция-член, любое состояние объекта. Если глобальная переменная изменяет выходные данные функции, тогда функция должна быть реструктурирована.

1
ответ дан 7 November 2019 в 07:15
поделиться

Это плохое использование assert, ИМХО. Утверждение не предназначено как инструмент сообщения об ошибках, оно предназначено для утверждения предварительных условий. Если Result не используется в другом месте, это не является предварительным условием.

2
ответ дан 7 November 2019 в 07:15
поделиться

Вы можете использовать:

Check( Func() == 1 );

И реализовать функцию проверки (bool), как хотите. Он может либо использовать assert, либо выдать конкретное исключение, записать в файл журнала или в консоль, иметь разные реализации в отладке и выпуске, либо в виде комбинации всех.

3
ответ дан 7 November 2019 в 07:15
поделиться
int Result = Func();
assert( Result == 1 );

This situation means that in release mode, you really want:

Func();

But Func is non-void, i.e. it returns a result, i.e. it is a query.

Presumably, besides returning a result, Func modifies something (otherwise, why bother calling it and not using its result?), i.e. it is a command.

By the command-query separation principle (1), Func shouldn't be a command and a query at the same time. In other words, queries shouldn't have side effects, and the "result" of commands should be represented by the available queries on the object's state.

Cloth c;
c.Wash(); // Wash is void
assert(c.IsClean());

Is better than

Cloth c;
bool is_clean = c.Wash(); // Wash returns a bool
assert(is_clean);

The former doesn't give you any warning of your kind, the latter does.

So, in short, my answer is: don't write code like this :)

Update (1): You asked for references about the Command-Query Separation Principle. Wikipedia is rather informative. I read about this design technique in Object Oriented Software Construction, 2nd Editon by Bertrand Meyer.

Update (2): j_random_hacker comments "OTOH, every "command" function f() that previously returned a value must now set some variable last_call_to_f_succeeded or similar". This is only true for functions that don't promise anything in their contract, i.e. functions that might "succeed" or not, or a similar concept. With Design by Contract, a relevant number of functions will have postconditions, so after "Empty()" the object will be "IsEmpty()", and after "Encode()" the message string will be "IsEncoded()", with no need to check. In the same way, and somewhat symetrically, you don't call a special function "IsXFeasible()" before each and every call to a procedure "X()"; because you usually know by design that you're fulfilling X's preconditions at the point of your call.

8
ответ дан 7 November 2019 в 07:15
поделиться

Вы можете создать другой макрос, который позволит вам избежать использования временной переменной:

#ifndef NDEBUG
#define Verify(x) assert(x)
#else
#define Verify(x) ((void)(x))
#endif

// asserts that Func()==1 in debug mode, or calls Func() and ignores return
// value in release mode (any braindead compiler can optimize away the comparison
// whose result isn't used, and the cast to void suppresses the warning)
Verify(Func() == 1);
9
ответ дан 7 November 2019 в 07:15
поделиться

Я не смог бы дать лучшего ответа, чем этот, который решает эту и многие другие проблемы:

Глупые трюки C ++: приключения в assert

#ifdef NDEBUG
#define ASSERT(x) do { (void)sizeof(x);} while (0)
#else
#include <assert.h>
#define ASSERT(x) assert(x)
#endif
27
ответ дан 7 November 2019 в 07:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: