What is the difference between using a struct with two fields and a pair?
std::pair
provides pre-written constructors and comparison operators. This also allows them to be stored in containers like std::map without you needing to write, for example, the copy constructor or strict weak ordering via operator <
(such as required by std::map
). If you don't write them you can't make a mistake (remember how strict weak ordering works?) so it's more reliable just to use std::pair
.
struct with 2 cells vs std::pair?
A pair
is implemented as a templated struct
. It provides you with a shorthand for creating a (typically heterogenous) pair. Also, there are some constraints on the types that you can use with a pair
:
Type requirements
T1 and T2 must both
be models of Assignable. Additional
operations have additional
requirements. Pair's default
constructor may only be used if both
T1 and T2 are DefaultConstructible,
operator== may only be used if both T1
and T2 are EqualityComparable, and
operator< may only be used if both T1
and T2 are LessThanComparable.
(from SGI STL std::pair
documentation)
Defining your own POD may make sense if the types do not follow any of these constraints or if you do not care about them.
Finally, I guess it is a matter of personal choice/coding style.
std::pairint, int vs struct with two int's
std::pair<int, int>::pair()
constructor initializes the fields with default values (zero in case of int
) and your struct Cell
doesn't (since you only have an auto-generated default constructor that does nothing).
Initializing requires writing to each field which requires a whole lot of memory accesses that are relatively time consuming. With struct Cell
nothing is done instead and doing nothing is a bit faster.
When should you use a class vs a struct in C++?
The differences between a class
and a struct
in C++ are:
struct
members and base classes/structs arepublic
by default.class
members and base classes/structs areprivate
by default.
Both classes and structs can have a mixture of public
, protected
and private
members, can use inheritance, and can have member functions.
I would recommend you:
- use
struct
for plain-old-data structures without any class-like features; - use
class
when you make use of features such asprivate
orprotected
members, non-default constructors and operators, etc.
Compare Two Structs Using Standard Method (Byte Comparison/Reflection) Even If Equals Method Exists
This can be done using reflection. The following solution is based on the code from the blog post Strong Typed, High Performance Reflection with C# Delegate, but the code has been shorten to work specifically for ValueType.Equals()
:
public static Func<ValueType, ValueType, bool> GetValueTypeEquals()
{
var type = typeof(ValueType);
var dynamicMethod = new DynamicMethod("ValueTypeEquals", typeof(bool), new[] { type, typeof(object) }, type);
var il = dynamicMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg, 0);
il.Emit(OpCodes.Ldarg, 1);
il.EmitCall(OpCodes.Call, type.GetMethod(nameof(Equals), Public | Instance, null, new[] { type }, null), null);
il.Emit(OpCodes.Ret);
return (Func<ValueType, ValueType, bool>) dynamicMethod.CreateDelegate(typeof(Func<ValueType, ValueType, bool>));
}
Using the method above to retrieve ValueTypes
's Equal()
method, the test from the example will look like this:
[Test]
public void PairsEqual()
{
var p1a = new Pair<int>(10, 1);
var p1b = new Pair<int>(10, 1);
var p2 = new Pair<int>(10, 2);
var equals = GetValueTypeEquals();
Assert.That(!equals(p1a, p2));
Assert.That(equals(p1a, p1a));
Assert.That(equals(p1a, p1b));
}
How to create a Vector where each entry is a structure with 2 fields
Use
public class Entry {
public String field1;
public String field2;
}
List<Entry> vector = ...;
Using different struct definitions to simulate public and private fields in C
- Am I overlooking something that may make this whole ordeal pointless, i.e. is there a simpler way to do this or is this explicitly discouraged, and if so, what are the objective reasons behind it.
Yes: your approach produces undefined behavior.
C requires that
All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.
(C17 6.2.7/2)
and that
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
- a type compatible with the effective type of the object,
- a qualified version of a type compatible with the effective type of the object,
[...]
- an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a
subaggregate or contained union), or- a character type.
(C17 6.5/7, a.k.a. the "Strict Aliasing Rule")
Your two definitions of struct ExampleStruct
define incompatible types because they specify different numbers of members (see C17 6.2.7/1 for more details on structure type compatibility). You will definitely have problems if you pass instances by value between functions relying on different of these incompatible definitions. You will have trouble if you construct arrays of them, whether dynamically, automatically, or statically, and attempt to use those across boundaries between TUs using one definition and those using another. You may have problems even if you do none of the above, because the compiler may behave unexpectedly, especially when optimizing. DO NOT DO THIS.
Other alternatives:
Opaque pointers. This means you do not provide any definition of
struct ExampleStruct
in those TUs where you want to hide any of its members. That does not prevent declaring and using pointers to such a structure, but it does prevent accessing any members, declaring new instances, or passing or receiving instances by value. Where member access is needed from TUs that do not have the structure definition, it would need to be mediated by accessor functions.Just don't access the "private" members. Do not document them in the public documentation, and if you like, explicity mark them (in code comments, for example) as reserved. This approach will be familiar to many C programmers, as it is used a lot for structures declared in POSIX system headers.
Related Topics
Ternary Conditional and Assignment Operator Precedence
Assembly Adc (Add with Carry) to C++
"Undefined Symbols" Linker Error with Simple Template Class
Is It Ok to Use C-Style Cast for Built-In Types
Stopping the Debugger When a Nan Floating Point Number Is Produced
Why Doesn't C++ Move Construct Rvalue References by Default
Using Maven for C/C++ Projects
What Is Different Between Join() and Detach() for Multi Threading in C++
Why Does Reallocating a Vector Copy Instead of Moving the Elements
Why Does a Push_Back on an Std::List Change a Reverse Iterator Initialized with Rbegin
Why Are Forward Declarations Necessary
C++ Overloaded Function as Template Argument
Is Infinite Loop Still Undefined Behavior in C++ If It Calls Shared Library