Using -1 as a flag value for unsigned (size_t) types

元气小坏坏 提交于 2019-11-26 13:49:05

-1 will always convert to the max unsigned value, this is due to section 4.7 Integral conversions:

If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type). [ Note: In a two’s complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). —end note ]

The same quote for C99 would be from 6.3.1.3:

Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.49)

So we end up with:

-1 + (UMAX + 1)

which is:

UMAX

The obvious caveat lies in the case of a set of elements with a size equal to the largest size possible. The possibility and usability of this happening in practice and actually being the cause of your problem at that point are negligible.

If you look at the C++ std::string class, you will notice the static std::string::npos data member is defined as exactly -1 converted to std::string::size_type (which is really just std::size_t. That gives this "technique" a sense of precedence, which allows it to fullfil The Principle of Least Surprise™, which is always a Good Thing®.

Now, using -1 directly in a comparison like that is asking for trouble. You should, as in the std::string case, ensure there is an accessible name for this value that will ensure its special meaning. unfortunately, the C++ type system isn't strict enough for this to prevent a user from shooting himself in the foot, but at least a user adhering to documented best practice won't think of doing things differently.

After trying to think of ways this might go wrong, I realized that there's a danger that the calling function might implicitly cast the return value to a larger type (ie unsigned int to unsigned long long). Then checking if that value == -1 will be false.

The safer option is to explicitly use size_t.max as the sentinel value. I'm always uncomfortable with changing between signed and unsigned types. Sometimes I think the more reasonable approach is to just make everything signed (like Java does).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!