I've been using overloaded operators as demonstrated in the second answer from here: How to use C++11 enum class for flags ... example:
#define ENUMFLAGOPS(EnumName)\
[[nodiscard]] __forceinline EnumName operator|(EnumName lhs, EnumName rhs)\
{\
return static_cast<EnumName>(\
static_cast<std::underlying_type<EnumName>::type>(lhs) |\
static_cast<std::underlying_type<EnumName>::type>(rhs)\
);\
}...(other operator overloads)
enum class MyFlags : UINT //duplicated in JS
{
None = 0,
FlagA = 1,
FlagB = 2,
FlagC = 4,
};
ENUMFLAGOPS(MyFlags)
...
MyFlags Flags = MyFlags::FlagA | MyFlags::FlagB;
And I've grown concerned that this may be producing undefined behavior. I've seen it mentioned that merely having an enum class variable that is not equal to one of the defined enum values is undefined behavior. The underlying UINT value of Flags in this case is 3. Is this undefined behavior? And if so, what would be the right way to do this in c++20?
It's a misconception that an enum type has only the values it declares.
Enums have all the values of the underlying type. It's just that in an enum some of these values have names. It's perfectly fine to obtain a value that has no name by static_casting or in the case of classical enums by operations (|) or simple assignment.
Your code is perfectly fine (outside of maybe raising some eyebrows for the macro use).
9.7.1 Enumeration declarations [dcl.enum]
For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type.
For enumerations whose underlying type is not fixed (i.e. : std::uint32_t is missing) the standard says basically the same thing, but in a more convoluted way: the enum has the same values as the underlying type, but there are more rules about what the underlying type is.
This is outside the scope of your question but you can define your operators without any macros and I highly recommend it:
template <class E>
concept EnumFlag = std::is_enum_v<E> && requires() { {E::FlagTag}; };
template <EnumFlag E>
[[nodiscard]] constexpr E operator|(E lhs, E rhs)
{
return static_cast<E>(std::to_underlying(lhs) | std::to_underlying(rhs));
}
enum class MyFlags : std::uint32_t
{
None = 0x00,
FlagA = 0x01,
FlagB = 0x02,
FlagC = 0x04,
FlagTag = 0x00,
};
Yes, you can have multiple "names" (enumerators) with the same value. Because we don't don't use the FlagTag value it doesn't matter what value it has.
To mark enums for which you want the operators defined you can use a tag like in the above example or you can use a type trait:
template <class E>
struct is_enum_flag : std::false_type {};
template <>
struct is_enum_flag<MyFlags> : std::true_type {};
template <class E>
concept EnumFlag = is_enum_flag<E>::value;
Neither the C nor C++ Standard make any distinction between actions which would be Undefined Behavior if examined in isolation without knowledge of things like types' bit patterns and associated trap representations (or lack thereof), versus those whose "Undefinedness" trumps any knowledge one might have about such things. This philosophy is perhaps best illustrated by the way the C99 Standard changed the treatment of x<<1 when x is negative; I the C++ Standard may have some better examples, but I'm not as familiar with it.
If a platform had an 8-bit store instruction that was faster than the normal ones except that attempting to store a bit pattern of 1100 0000 would cause the CPU to overheat and melt, I don't think anything in the C++ Standard would forbid a C++ implementation from offering an int_least7_t extended type that uses that store instruction, and using such a type to represent an enum whose type was unspecified, and whose values included -63 and -62, but not -64. If one couldn't be certain that code would not be run on such a platform, one couldn't know whether attempting to execute myEnum1 = (myEnumType)((int)myEnum2 & (int)myEnum3); when myEnum2 and myEnum3 hold -63 and -62, respectively, might set the CPU on fire. Thus the latter construct would be--as far as the Standard is concerned--Undefined Behavior.
Both the C and C++ Standards are caught between a rock and a hard place between some people who think there should be no need for the Standard to add new text to say that constructs which had been processed consistently for decades should continue to be, and others who view the lack of any such mandate as an invitation to throw longstanding practices out the window. The only way one can know whether any particular construct should be expected to work is to know whether the people responsible for target implementations respect precedent or view it as an impediment to "optimization".
Related
Let's say I have defined a zero_initialize() function:
template<class T>
T zero_initialize()
{
T result;
std::memset(&result, 0, sizeof(result));
return result;
}
// usage: auto data = zero_initialize<Data>();
Calling zero_initialize() for some types would lead to undefined behavior1, 2. I'm currently enforcing T to verify std::is_pod. With that trait being deprecated in C++20 and the coming of concepts, I'm curious how zero_initialize() should evolve.
What (minimal) trait / concept can guarantee memsetting an object is well defined?
Should I use std::uninitialized_fill instead of std::memset? And why?
Is this function made obsolete by one of C++ initialization syntaxes for a subset of types? Or will it be with the upcoming of future C++ versions?
1) Erase all members of a class.
2) What would be reason for “undefined behaviors” upon using memset on library class(std::string)? [closed]
There is technically no object property in C++ which specifies that user code can legally memset a C++ object. And that includes POD, so if you want to be technical, your code was never correct. Even TriviallyCopyable is a property about doing byte-wise copies between existing objects (sometimes through an intermediary byte buffer); it says nothing about inventing data and shoving it into the object's bits.
That being said, you can be reasonably sure this will work if you test is_trivially_copyable and is_trivially_default_constructible. That last one is important, because some TriviallyCopyable types still want to be able to control their contents. For example, such a type could have a private int variable that is always 5, initialized in its default constructor. So long as no code with access to the variable changes it, it will always be 5. The C++ object model guarantees this.
So you can't memset such an object and still get well-defined behavior from the object model.
What (minimal) trait / concept can guarantee memsetting an object is well defined?
Per the std::memset reference on cppreference the behavior of memset on a non TriviallyCopyable type is undefined. So if it is okay to memset a TriviallyCopyable then you can add a static_assert to your class to check for that like
template<class T>
T zero_initialize()
{
static_assert(std::is_trivial_v<T>, "Error: T must be TriviallyCopyable");
T result;
std::memset(&result, 0, sizeof(result));
return result;
}
Here we use std::is_trivial_v to make sure that not only is the class trivially copyable but it also has a trivial default constructor so we know it is safe to be zero initialized.
Should I use std::uninitialized_fill instead of std::memset? And why?
You don't need to here since you are only initializing a single object.
Is this function made obsolete by one of C++ initialization syntaxes for a subset of types? Or will it be with the upcoming of future C++ versions?
Value or braced initialization does make this function "obsolete". T() and T{} will give you a value initialized T and if T doesn't have a default constructor it will be zero initialized. That means you could rewrite the function as
template<class T>
T zero_initialize()
{
static_assert(std::is_trivial_v<T>, "Error: T must be TriviallyCopyable");
return {};
}
The most general definable trait that guarantees your zero_initialize will actually zero-initialize objects is
template <typename T>
struct can_zero_initialize :
std::bool_constant<std::is_integral_v<
std::remove_cv_t<std::remove_all_extents_t<T>>>> {};
Not too useful. But the only guarantee about bitwise or bytewise representations of fundamental types in the Standard is [basic.fundamental]/7 "The representations of integral types shall define values by use of a pure binary numeration system." There is no guarantee that a floating-point value with all bytes zero is a zero value. There is no guarantee that any pointer or pointer-to-member value with all bytes zero is a null pointer value. (Though both of these are usually true in practice.)
If all non-static members of a trivially-copyable class type are (arrays of) (cv-qualified) integral types, I think that would also be okay, but there's no possible way to test for that, unless reflection comes to C++.
Let's say I have defined a zero_initialize() function:
template<class T>
T zero_initialize()
{
T result;
std::memset(&result, 0, sizeof(result));
return result;
}
// usage: auto data = zero_initialize<Data>();
Calling zero_initialize() for some types would lead to undefined behavior1, 2. I'm currently enforcing T to verify std::is_pod. With that trait being deprecated in C++20 and the coming of concepts, I'm curious how zero_initialize() should evolve.
What (minimal) trait / concept can guarantee memsetting an object is well defined?
Should I use std::uninitialized_fill instead of std::memset? And why?
Is this function made obsolete by one of C++ initialization syntaxes for a subset of types? Or will it be with the upcoming of future C++ versions?
1) Erase all members of a class.
2) What would be reason for “undefined behaviors” upon using memset on library class(std::string)? [closed]
There is technically no object property in C++ which specifies that user code can legally memset a C++ object. And that includes POD, so if you want to be technical, your code was never correct. Even TriviallyCopyable is a property about doing byte-wise copies between existing objects (sometimes through an intermediary byte buffer); it says nothing about inventing data and shoving it into the object's bits.
That being said, you can be reasonably sure this will work if you test is_trivially_copyable and is_trivially_default_constructible. That last one is important, because some TriviallyCopyable types still want to be able to control their contents. For example, such a type could have a private int variable that is always 5, initialized in its default constructor. So long as no code with access to the variable changes it, it will always be 5. The C++ object model guarantees this.
So you can't memset such an object and still get well-defined behavior from the object model.
What (minimal) trait / concept can guarantee memsetting an object is well defined?
Per the std::memset reference on cppreference the behavior of memset on a non TriviallyCopyable type is undefined. So if it is okay to memset a TriviallyCopyable then you can add a static_assert to your class to check for that like
template<class T>
T zero_initialize()
{
static_assert(std::is_trivial_v<T>, "Error: T must be TriviallyCopyable");
T result;
std::memset(&result, 0, sizeof(result));
return result;
}
Here we use std::is_trivial_v to make sure that not only is the class trivially copyable but it also has a trivial default constructor so we know it is safe to be zero initialized.
Should I use std::uninitialized_fill instead of std::memset? And why?
You don't need to here since you are only initializing a single object.
Is this function made obsolete by one of C++ initialization syntaxes for a subset of types? Or will it be with the upcoming of future C++ versions?
Value or braced initialization does make this function "obsolete". T() and T{} will give you a value initialized T and if T doesn't have a default constructor it will be zero initialized. That means you could rewrite the function as
template<class T>
T zero_initialize()
{
static_assert(std::is_trivial_v<T>, "Error: T must be TriviallyCopyable");
return {};
}
The most general definable trait that guarantees your zero_initialize will actually zero-initialize objects is
template <typename T>
struct can_zero_initialize :
std::bool_constant<std::is_integral_v<
std::remove_cv_t<std::remove_all_extents_t<T>>>> {};
Not too useful. But the only guarantee about bitwise or bytewise representations of fundamental types in the Standard is [basic.fundamental]/7 "The representations of integral types shall define values by use of a pure binary numeration system." There is no guarantee that a floating-point value with all bytes zero is a zero value. There is no guarantee that any pointer or pointer-to-member value with all bytes zero is a null pointer value. (Though both of these are usually true in practice.)
If all non-static members of a trivially-copyable class type are (arrays of) (cv-qualified) integral types, I think that would also be okay, but there's no possible way to test for that, unless reflection comes to C++.
Let I be some integral type. Now suppose I have a enum class my_enum_class : I, with values which may not be consecutive. And now I get some I value. How do I check whether it's a value enumerated in my_enum_class?
An answer to a similar question (for the C language) makes the assumption that values are contiguous, and that one can add a "dummy" upper-bound value, and check the range between 0 and that value; that's not relevant in my case. Is there another way to do it?
There is currently no way to do this.
There are reflection proposals that may make it into c++20 and/or c++23 that let you iterate (at compile, and hence run, time) over the enumerated values in an enum. Using that the check would be relatively easy.
Sometimes people do manual enum reflection, often using macros.
There is no built-in way to do this. All Is are "valid" values of my_enum_class, so you can't do anything with the underlying type. As for validating Is against the list of enumerators, without reflection there is simply no way to do it.
Depending on the context, I tend to either build a static std::unordered_set (and do lookups into that), or have a function listing all my enumerators in a switch (and returning false iff the input matches none of them), or just not bother, instead documenting somewhere that passing an unenumerated my_enum_class value to my functions shall be deemed impish trickery and have unspecified behaviour.
Ultimately this all stems from the fact that enums are supposed to list "common conveniently named values" within a wider range of totally valid states, rather than a type comprised only of a fully constrained set of constants. We pretty much all abuse enums.
Though the standard doesn't yet allow you to do introspection, there is a small workaround you could use, that can possibly be improved with ADL. Courtesy to this older answer.
namespace sparse {
template<typename E>
constexpr bool in_(std::underlying_type_t<E> i) { return false; }
template<typename E, E value, E...values>
constexpr bool in_(std::underlying_type_t<E> e) {
return static_cast<E>(e) == value || in_<E, values...>(e);
}
}
To be used like this:
enum class my_enum: int { a=3, b=4 };
template<>
constexpr auto sparse::in<my_enum> =
in_<my_enum, my_enum::a, my_enum::b>;
static_assert(sparse::in<my_enum>(3));
static_assert(sparse::in<my_enum>(4));
static_assert(!sparse::in<my_enum>(5))
I want to represent a single variable of type U as an array of type-T elements, for use at compile time. sizeof(T) divides sizeof(U) perfectly, so letting k = sizeof(U)/sizeof(T) it should be an std::array<T, k>.
Problem is, how do I construct it (again, at compile time)? Can/should I use casting, i.e.
* (reinterpret_cast<std::array<T,k> *>(&my_u))
or maybe some sort of recursive function call setting its elements? Or is there some better/nicer way?
The correct way to alias value representations is almost always to use memcpy:
std::array<T, k> my_t;
static_assert(sizeof(my_t) == sizeof(my_u), "!!");
std::memcpy(my_t.data(), &my_u, sizeof(my_u));
There is no "nicer" way, as you will need to use memcpy at some point to bypass strict aliasing restrictions (unless T is a narrow character type).
At compile time, this is in general impossible as the C++ Standard does not e.g. describe the layout of bits within floating-point types, or whether integral types are little-, big- or mixed-endian. This may be possible in some restricted instances, but you will not be able to use memcpy or reinterpret_cast, so will have to write type-specific code to access the members of U individually.
The best way to structure your code might be to write a collection of functions extracting values of type T from a value of type U at a specific offset:
constexpr T getValueOfTAtOffset(U u, std::integral_constant<std::size_t, 0>) { ... }
constexpr T getValueOfTAtOffset(U u, std::integral_constant<std::size_t, 1>) { ... }
// ...
You would then call them using an index_sequence template inference:
template<std::size_t... I>
constexpr std::array<T, sizeof...(I)> asArrayOfTImpl(U u, std::integer_sequence<std::size_t, I...>) {
return {getValueOfTAtOffset(u, std::integral_constant<std::size_t, I>{})};
}
constexpr std::array<T, k> asArrayOfT(U u) {
return asArrayOfTImpl(u, std::make_index_sequence<k>{});
}
C++ (and C) has a feature known as strict aliasing.
Strict aliasing states that a pointer to T and a pointer to U are never pointers to the same data.
One reason behind this rule is that it permits a whole bunch of optimizations. If you have a int and you dereference an short* and modify it, you know that the int was not modified without having to chase pointers.
Which means you can only reinterpret cast an X* to a Y* if the pointer was originally actually a Y*, or one of the execptions apply.
These exceptions include Y being a char type, or the layout-compatibility guarantees that basically talk about one structure being a prefix of another in certain standard layout cases.
In the general case, these do not apply. So you must either seek out one of these exceptions, or use memcpy to marshall your data through one of these exceptions, to be standard-compliant.
The risk here is that aggressive compiler optmizations can significantly change the apparent meaning of your code when faced with blatant undefined behavior. Even if you test it and it works, the next compiler version is justified in making your code break in various and sundry ways, or an innocuous compiler option flag, or anything else.
One option you can do is create a union. But even there, access of the "wrong" part of the union is undefined behavior, barring standard layout guarantees.
A more specific set of information about your data might actually provide a way around it -- possibly you are satisfying the standard layout guarantees, for example -- but they are easy to break.
I have looked at the following — related — questions, and none of them seem to address my exact issue: one, two, three.
I am writing a collection of which the elements (key-value pairs) are stored along with some bookkeeping information:
struct Element {
Key key;
Value value;
int flags;
};
std::vector<Element> elements;
(For simplicity, suppose that both Key and Value are standard-layout types. The collection won't be used with any other types anyway.)
In order to support iterator-based access, I've written iterators that override operator-> and operator* to return to the user a pointer and a reference, respectively, to the key-value pair. However, due to the nature of the collection, the user is never allowed to change the returned key. For this reason, I've declared a KeyValuePair structure:
struct KeyValuePair {
const Key key;
Value value;
};
And I've implemented operator-> on the iterator like this:
struct iterator {
size_t index;
KeyValuePair *operator->() {
return reinterpret_cast<KeyValuePair *>(&elements[index]);
}
};
My question is: is this use of reinterpret_cast well-defined, or does it invoke undefined behavior? I have tried to interpret relevant parts of the standard and examined answers to questions about similar issues, however, I failed to draw a definitive conclusion from them, because…:
the two struct types share some initial data members (namely, key and value) that only differ in const-qualification;
the standard does not explicitly say that T and cv T are layout-compatible, but it doesn't state the converse either; furthermore, it mandates that they should have the same representation and alignment requirements;
Two standard-layout class types share a common initial sequence if the first however many members have layout-compatible types;
for union types containing members of class type that share a common initial sequence, it is permitted to examine the members of such initial sequence using either of the union members (9.2p18).
– there's no similar explicit guarantee made about reinterpret_casted pointers-to-structs sharing a common initial sequence.
– it is, however, guaranteed that a pointer-to-struct points to its initial member (9.2p19).
Using merely this information, I found it impossible to deduce whether the Element and KeyValuePair structs share a common initial sequence, or have anything other in common that would justify my reinterpret_cast.
As an aside, if you think using reinterpret_cast for this purpose is inappropriate, and I'm really facing an XY problem and therefore I should simply do something else to achieve my goal, let me know.
My question is: is this use of reinterpret_cast well-defined, or does
it invoke undefined behavior?
reinterpret_cast is the wrong approach here, you're simply violating strict aliasing. It is somewhat perplexing that reinterpret_cast and union diverge here, but the wording is very clear about this scenario.
You might be better off simply defining a union thusly:
union elem_t {
Element e{}; KeyValuePair p;
/* special member functions defined if necessary */
};
… and using that as your vector element type. Note that cv-qualification is ignored when determining layout-compability - [basic.types]/11:
Two types cv1 T1 and cv2 T2 are layout-compatible types if
T1 and T2 are the same type, […]
Hence Element and KeyValuePair do indeed share a common initial sequence, and accessing the corresponding members of p, provided e is alive, is well-defined.
Another approach: Define
struct KeyValuePair {
Key key;
mutable Value value;
};
struct Element : KeyValuePair {
int flags;
};
Now provide an iterator that simply wraps a const_iterator from the vector and upcasts the references/pointers to be exposed. key won't be modifiable, but value will be.