Is it relevant to use nested struct? - c++

I'm trying to define a class that has private struct and public struct.
Private struct is the struct that will only be used by the class (e.g. SNode), and I don't want it to be visible outside the class because I don't want it to be mistakenly used (e.g. new Node()). Thus, I reached to the idea to set it basically hidden.
Public struct is the struct that will be used outside (e.g. SKeyValuePair), and it will have a pointer to a SNode.
Code Example is below.
[Class Definition]
template <typename T>
class A
{
private:
struct SNode
{
SNode* pParentNode;
SNode* pLeftChildNode;
SNode* pRightChildNode;
...
};
public:
A<T>()
{
}
virtual ~A()
{
}
struct SPair
{
private:
public:
SNode* pNode;
unsigned long long ullKey;
T value;
...
};
const SPair GetMinKeyPair()
{
return SPair(...);
}
const SPair GetNextMinKeyPair()
{
...
return SPair(...);
}
};
[Usage]
A a;
...
for (A::SPair pair = a.GetMinKeyPair(); pair.pNode != nullptr; pair = a.GetNextMinKeyPair())
{
...
}
Q1. I wonder if this kind of nested struct (which public struct containing private struct pointer) should be avoided for some reason I currently don't know.
Q2. If there are reasons, I wonder what they are.

In general, this is not a bad way to do business.
It keeps the name SNode<T> private when it doesn't need to be public. (Though, as aschepler noted in comments, be aware that the type itself can still be used in full via auto; accessibility affects only names.)
So this is quite a neat way to organise things, and I do personally make use of nested types.
However, since A is a class template, you're going to have a copy of SNode for each T that you use. That's just how templates work. This means more code and a larger executable. For that reason, you might consider the more conventional approach of just putting the utility types in a namespace instead. Does it really matter whether people try to use them outside of A<T>?

Related

Workaround for using a private struct

I am using an engine for my console application. This engine can not be changed. The engine contains a class called Mesh. There's a public method in this class findBoundaryLoops() which I'm using in my class (which is not part of the engine) but I have to pass a parameter to this method which type VertexLoop is defined as a private attribute. I'm not sure that I explain it well, so there's a representation of the code:
Mesh.h:
class Mesh final
{
private:
...
struct VertexNode
{
Edge connectingEdgeWithNext;
Vertex vertex;
VertexNode* prev;
VertexNode* next;
float angle;
};
struct VertexLoop
{
VertexNode* firstNode;
uint32_t nodeCount;
template<typename Callable>
void forEachNode(Callable&& f)
{
VertexNode* n = firstNode;
for (uint32_t i = 0; i < nodeCount; ++i, n = n->next)
{
f(n);
}
}
};
...
public:
...
void findBoundaryLoops(memory::MemoryArena& arena, vector<VertexLoop>& loops) const;
...
};
I have to use the findBoundaryLoops() method, but the VertexLoop struct is private. Is there a workaround or something to solve this problem?
This answer has two parts. Below I will show you how to access the type declared in the private section. But I think the important point, and thats why I put it first, is to realize that you should not need the below solution. Anybody can access VertexLoop. The name is private the type not. There was no point to declare it in the private section in the first place. If the type appears on the signature of a public method you can as well put it in the public section.
If this is library code or generated code, then either you misunderstand how to use it, or it can be considered broken.
Simpler example:
#include <vector>
struct foo {
private:
struct bar{};
public:
void f(std::vector<bar>&){}
};
Now we write a trait that given a member function of foo with a single vector parameter tells us the value_type of that vector. Then we instantiate it with a pointer to foo::f to get an alias to bar:
template <typename X>
struct bar_type;
template <typename T> struct bar_type< void(foo::*)(std::vector<T>&)> { using type = T; };
using public_bar = bar_type<decltype(&foo::f)>::type;
Using it:
int main() {
std::vector<public_bar> v;
foo f;
f.f(v);
}
Live Demo
Maybe worth to note that this is by no means comparable to "dirty hacks" by which one can access private members of a class (yes they do exist). This is not a hack, it is perfectly fine partial specialization of a trait to get the parameter type of a public method.
TL;DR Just don't do it. Move VertexLoop to the public section.

Casting an object to a derived class to access protected members of parent class

I'm trying to access a protected member of a class defined and implemented by an external library. I'd like to achieve that without copying or moving the instance if possible.
Here is a simplified example. Let's say this is the code from the external library:
// some_external_library.h
class Node {
public:
static Node Create();
protected:
Node(int val) : val_(val) {}
int val_;
};
This is what I am trying to do:
// my_code.cpp
#include "some_external_library.h"
Node node = Node::Create();
int val = node.val_; // <-- This is invalid since val_ is protected.
Node class is part of some external library that I link to my program. So, I'd like to avoid modifying Node class by adding a public function or friend declaration for accessing val_. Also, I'd like to avoid creating a copy of node object or moving from it, so I'd like to avoid creating a derived class moving/copying the Node instance just to access a member field. Is it possible?
I came up with a possible solution, which worked fine for the minimal example:
// my_code.cpp
#include "some_external_library.h"
class NodeAccessor : public Node {
public:
int val() const { return val_; }
};
Node node = Node::Create();
int val = static_cast<const NodeAccessor&>(node).val();
However, I'm not sure if this is valid since node isn't an instance of NodeAccessor. Is this standard compliant? Would it cause any problems (e.g. optimizing away of val_ during compilation of the external library)?
What you do is UB.
There is one magical way to access private/protected member in C++:
The ISO C++ standard specifies that there is no access check in case of explicit template instantiations, and following code abuse of that:
template <typename Tag>
struct result
{
using type = typename Tag::type;
static type ptr;
};
template <typename Tag> typename result<Tag>::type result<Tag>::ptr;
template<typename Tag, typename Tag::type p>
struct rob : result<Tag> {
/* fill it ... */
struct filler {
filler() { result<Tag>::ptr = p; }
};
static filler filler_obj;
};
template <typename Tag, typename Tag::type p>
typename rob<Tag, p>::filler rob<Tag, p>::filler_obj;
And then
struct NodeVal { using type = int Node::*; };
template class rob<NodeVal, &Node::val_>;
and finally:
int main() {
Node node = /**/;
(node.*result<NodeVal>::ptr);
}
Demo
Yes, that can and will and should cause problems.
You are casting a thing to a type, then the thing is not of that type.
All manner of antics can ensue as a result.
There is simply no way to do what you're trying to do, and that's a good thing! Access protections are there for a reason. Work with them, not against them.

OO design for intrusive data structure

I'm writing an intrusive linked list
class ListAlgorithm {
ListNode& next(ListNode& n) {
//returns an object of type ListNode linked to n.
}
};
Users usually want to add some features (such as some additional data) on ListNode like this:
class UserNode : public ListNode {
void operationOnUserData();
int userData;
};
Then users have to downcast ListNode returned by 'next' into UserNode. It is inconvenient. Thus, I tried to make ListAlgorithm a template class :
//U extends ListNode
template<class U>
class ListAlgorihtm {
U& next(U& u);
};
But then I have to upcast u into ListNode inside the method 'next' because class U could accidentally hide some members of ListNode that ListAlgorithm uses. This is error-prone because I could forget the upcast and compiler will not warn about that. I have to downcast ListNode into U again for the return value but it is safe because 'next' takes an instance u of U and the return value is something from u.
Another trial is
//U extends ListNode
template<class U>
class ListAlgorhtm {
U& next(ListNode& n);
};
In this case, the upcast problem is not there, but I have to downcast ListNode into U for the return value and it is not safe because it is not sure that n is an instance of U. It could be an instance of another type extending ListNode.
What is the best solution in this case? I think this is a very elementary design problem and I'd like to know what kind of material I have to study for basic OO design like this.
Your actual problem here is that you allow users to subclass ListNode and mess with its semantics by adding arbitrary data and operations to ListNode objects through subclassing. This therefore makes it necessary for the user to interpret the ListNode& return values of actual ListNode methods as something that those return values are not, semantically speaking.
This problem of a semantic nature is reflected in how tedious your code suddenly becomes, with casts and templating of an unrelated class (ListAlgorithm) which is due to your problem "propagating" and infecting other parts of your code.
Here's a solution: a ListNode object should not be allowed to also be a UserNode object. However, it should be allowed to have, to carry with it a UserData object that can be retrieved and manipulated.
In other words, your list becomes a simple container template, like std::list, and the users can specify the operations and data members that they need as part of the definition of the class they use as the template argument.
class IListNode
{
public:
// whatever public methods you want here
protected:
// pure virtual methods maybe?
};
class ListNode : public IListNode
{
// List node class, no data
};
template<class UserDataType>
class ListNodeWithData : public IListNode
{
private:
UserDataType data;
public:
ListNodeWithData <UserDataType>(UserDataType &data) :
data(data)
{ }
const UserDataType& getData() {
return data;
}
};
class ListAlgorithm
{
public:
template<class UserDataType>
ListNodeWithData<UserDataType>& next(const ListNodeWithData<UserDataType>& node) {
// Do stuff
}
ListNode& next(const ListNode& node) {
// Do stuff, which may be very similar to the stuff done above
// in which case you may want to prefer to just define the
// method below, and remove this one and the one above:
}
// You should define either this method or the two above, but having
// them all is possible too, if you find a use for it
IListNode& next(const IListNode& node) {
// Do generic stuff
}
};
As far as the size of the resulting classes is concerned, I just know it will increase if you use virtual methods in IListNode.
As far as the issue you raise goes, any time you want to operate on members of a class and avoid hiding by a derived class, just make sure your operations are on the base, so
template<class U>
class ListAlgorihtm {
public:
U& next(U& u) {
return static_cast<U&>(return nextNode(u));
}
private:
ListNode& nextNode(ListNode& n);
};
That said, you have a lot of options for this problem set. The Boost library has an "intrusive" library that embeds node information either as base_hook (as a base of the user data) or member_hook (as a member of the class, which avoids some of the problems you describe). Check it out at http://www.boost.org/doc/libs/1_57_0/doc/html/intrusive.html.

Details and benefits of using a struct in a class definition

Consider the following code:
class myclass
{
public:
//some public stuff
private:
struct classitem
{
int x;
classitem *next;
};
}
What I do not understand is this;
Is classitem just a definition, or will it already be a member of an object of this class? In other words, will it be filling any memory when we create an object of this class? If it is just a definition, how would we use it in future?
And what would be the benefits of using this struct in class definition instead of defining it outside of the class?
It will be just a definition.
If you want an object, use:
struct T { ... } instance;
The inner struct will be scoped in the outer struct definition - as to why it's useful, you can make the type (class) definition private for instance, if you don't want that type to be used outside of your class.
class NHeadedBeast {
struct Head {
Head() : numHeads{2}, eyesPerHead{4} { }
int numHeads;
int eyesPerHead;
} head;
public:
int getEyeCount() const {
return head.eyesPerHead * head.numHeads;
}
};
Notice how specific the Head class is - and also, it's called Head, which has a decent chance of colliding with some other type name. In other words, noone would ever want to use that Head type without my NHeadedBeast class, so might as well make the type inaccessible and isolate it in the NHeadedBeast scope.

Container implementation for complex type

I'm trying to come up with a container wrapper which stores data of the following types: bool, int, double, std::string. In addition I have a complex type which I need to store in the container. Let's call it Foo. For the sake of simplicity we'll say that Foo contains a list of ints.
My container class currently wraps an ugly and complex container type which I get from a c api. When I'm finish manipulating the data in the container, I need to copy it back to the api. It uses unions and linked lists. It is possible that I can copy this data into, for example, a std::list, but this might cause performance issues which present themselves at a later date. Therefore, my container class is not dependant on how data is actually stored in memory.
Here's a quick idea of how my container looks:
template <class T>
class Cont
{
public:
Cont(ISetter<T>* setter)
: _setter(setter)
{
}
void sillyFunction(T t)
{
(*_setter)(t,0);
}
private:
...
ISetter<T>* _setter;
};
So I use a helper setter class which handles the nitty gritty of the memory. I have a number of these class but the ISetter will give you an idea of what I'm doing.
In order to deal with the Foo type, which is also stored by the c api in a rather bizarre way, I have arrived at the following setter. Again, this is just a rough example.
class IFoo
{
public:
virtual int getMember() = 0;
};
class Foo2: public IFoo
{
public:
virtual int getMember(){ return 1;} // dummy
};
template<typename T> class ISetter{};
template<> class ISetter<IFoo*>
{
public:
virtual void operator()(IFoo* value, int index) = 0;
};
template<typename T> class Setter{};
template<> class Setter2<Foo2*>: public ISetter<IFoo*>
{
public:
virtual void operator()(IFoo* value, int index)
{
_list[index] = dynamic_cast<Foo2*>(value);
}
private:
std::vector<Foo2*> _list;
};
So I handle my Foo as an interface called IFoo. The Setter2 implementation deals with the setting in memory of my list of Foos. Setter1, missing below, deals with the ugly c api memory.
Here's an idea of these class in practice:
Foo2* f = new Foo2();
ISetter<IFoo*>* setter = new Setter2<Foo2*>();
Cont<IFoo*>* container = new Cont<IFoo*>(setter);
container->sillyFunction(f);
When dealing with ints, for example, I do something like this instead:
int i = 10;
ISetter<int>* setter = new Setter1<int>();
Cont<int>* container = new Cont<int>(setter);
container->sillyFunction(i);
So, my question is if you think this is a good approach and what improvements you might recommend.
I use shared pointers instead of raw pointers.
I would create a single simple Foo wrapper class which can look up members data from the C API, and present it as a coherent class. No need for messing about with interfaces, virtual functions or inheritance for that. Just a single class will do.
So for each "Foo"-entry in the C API, you create a single Foo wrapper.
Then you have simple, well-behaved type representing individual instances of the data stored in your C library.
Now just take that and put it in a std::vector.
struct Foo {
Foo(<handle-or-pointer-to-library-data>);
// member functions for retrieving member data from the C API
};
std::vector<int>
std::vector<bool>
std::vector<std::string>
std::vector<Foo>
As I understand your problem, that would be a simple and efficient solution.
I would change it a little. Consider to remove all this Setter virtual-ism from your code. One of goal to introduce Templates were to have alternative to virtual-ism:
template <class T, class Setter>
class Cont
{
public:
Cont(Setter setter = Setter())
: _setter(setter)
{
}
void sillyFunction(T t)
{
_setter(t,0);
}
private:
...
Setter _setter;
};
And its simple usage:
template <class IType, class Type>
class Setter2_Virtual
{
public:
void operator()(IType* value, int index)
{
_list[index] = dynamic_cast<Type*>(value);
}
private:
std::vector<Type*> _list;
};
Cont<IFoo*, Setter2_Virtual<IFoo, Foo2> > container;
container.sillyFunction(f);
I concentrated on Setters - but maybe you can do the same with IFoo/Foo stuff as well.
Just an idea - you do not obliged to use it after all.