0

I am writing unit test cases, for which I have written some structures and their arrays which holds input data for them and correct results. Data is like this

.e.g to test sum(a,b) which returns a,b I have below code

struct Data
{
   const int a,b,c;  
};

Data arr[] = 
{
    {1,0,1};
    (2,1,3};
}

const unsigned int getsizeofarr()
{
    return sizeof(arr)/sizeof(arr[0]);
}

I am not sure if this is the best way to expose data in OOPS parlance. I have made variables const but const_cast can easily remove it and modify data. Let me know how to expose my test data so that it remains const and also accessible to test cases.

Thanks In Advance

anonymous
  • 1,920
  • 2
  • 20
  • 30
  • 2
    Using `const_cast` for removing const-ness here is UB, so I'm unclear why you're worried about it. A program that does so is ill-formed from the start. – WhozCraig Dec 19 '14 at 08:39
  • Can you give an example of what kind of access you are worried about? Also I'd recommend using std::vector or std::array – MikeMB Dec 19 '14 at 09:09
  • if C++11 is an option, use `constexpr`, perhaps combined with namespaces or classes with public static members. – rubenvb Dec 19 '14 at 09:52
  • if the data is intended to be read-only, it is perfectly acceptable to simply expose const data members. It's an extremely efficient (and thread-safe) way of exposing immutable data. There is absolutely no need for accessor methods. – Richard Hodges Dec 19 '14 at 12:22

3 Answers3

1

You could create accessor methods like this:

class Data
{
public:
  inline int GetA() const { return a; }
  inline int GetB() const { return b; }
  inline int GetC() const { return c; }
private:
  const int a, b, c;
};

Accessor methods are methods that do not alter the state of the object. They are simply methods used to control access to the data within the object by providing as extra layer of access. This way, the user will not have direct access and will have to go through the accessor methods to access the original data.

To avoid a const_cast from mutating your read-only data, the easiest way is to hide the memory location of your data, which means that the user must neither be able to get a reference nor a pointer to your data. This essentially means that you're left with providing the user with a copy of your data.

From your example, it seems you're only using ints, so returning a copy is generally inexpensive. However, imagine if you have a vector of 1000000 ints. Attempting to make a copy of that will be considerably expensive (just think about how you would make a copy of an array of 1000000 ints). In such cases where the size of the data is not trivial, you would want to return a read-only reference to the data instead to prevent any copying like so.

class Data
{
public:
  inline const std::array<int, 1000>& GetA() const { return a; }
  inline const std::array<int, 1000>& GetB() const { return b; }
  inline const std::array<int, 1000>& GetC() const { return c; }
private:
  const std::array<int, 1000> a, b, c;
};

So in the end, you'll have to make a judgement call. Is data security more important than performance? If so, hide the data and only return copies of the data. Otherwise, is the data of negligible size? If so, returning a reference might actually be more expensive than simply making a copy of the data, otherwise, return a read-only reference.

Pseudocode:

If security is more important than performance
  Return a copy
Otherwise
  If size of data is of negligible size
    Return a copy
  Otherwise
    Return a read-only reference
Community
  • 1
  • 1
Nard
  • 1,006
  • 7
  • 8
  • 1
    Not clear why the results of each member is `const int` and not simply `int`. The `const` *member* access is obvious, however. – WhozCraig Dec 19 '14 at 08:40
  • @WhozCraig Thanks for your input. I've edited my answer. Please take a look. – Nard Dec 19 '14 at 09:40
0

I am not sure if this is the best way to expose data in OOPS parlance. I have made variables const but const_cast can easily remove it and modify data. Let me know how to expose my test data so that it remains const and also accessible to test cases.

const_cast is not for removing const from data so you can modify it; that is UB. It should be instead used to remove const specifyer from data, when you need to call an API that is not marked as const (but that doesn't modify the data).

That said, consider letting client code decide what should be const or not. This will allow you to use Data instances more flexibly and specify constness on use (more explicit).

Code:

struct Data
{
   int a,b,c; // no const here
};

const std::array<Data, 2> arr = {
    {1,0,1};
    (2,1,3};
}; // const here

Also note: consider using at least a std::array: it offers better interface and safety over the same functionality as a raw array type.

utnapistim
  • 26,809
  • 3
  • 46
  • 82
0

Usually, you would not mark the members of your struct constant, but the Variable, you define:

struct Data { 
    int a,b,c; 
}; 

const Data arr[] = { {1,0,1}, {2,1,3} };

As already mentioned by others, you definitely should replace the c-style array with a std::vector or an std::array (that way you can also get rid of getsizeofarr).

MikeMB
  • 20,029
  • 9
  • 57
  • 102