Differencebetween Using a Struct with Two Fields and a Pair

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 are public by default.
  • class members and base classes/structs are private 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 as private or protected 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


  1. 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:

  1. 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.

  2. 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



Leave a reply



Submit