@H3YW0R1Ddispos,
1) When node is created, where is data initialized in the node? |
child = new node{v}
This uses initialization syntax, and older compilers might not understand it, though they should.
2) Where is memory allocated if data is a pointer or is it not? And it is a value? It cannot store the whole packet?
|
If any container from the STL is given a pointer type, that is the calling code's responsibility
std::vector< Packet * > vptr;
Since this vector is configured to accept Packet *, and not Packet, it operates as if the value is Packet *. The responsibility for allocation is the calling code (your code if you wrote it this way). That also means calling code is responsible for deleting all the Packets, as the container won't do it. This isn't commonly done this way. Instead, this concept may more commonly be used to prepare an alternate order of existing data. I sense you're not quite at that point, but consider something like:
1 2
|
VDat v[ 100 ];
std::map< std::string, VDat * > vkeyed;
|
Assume VDat is some kind of structure with various fields of data. It is in an array and could be sorted, but suppose you needed a separate lookup into v by other "keys" (like a list of customers, and you want to look up by phone).
This allows each instance in v to be keyed in vkeyed, where the pointer to any entry in v can be cross referenced. In this case v is the storage, so the pointers in vkeyed do not require deletion.
My intention has always been to allocate memory to data and take in the address of the inserting packet via. pointer. Is that not a good idea? What you're saying is to copy the contents of Packet into data instead, creating a new copy?
|
1 2 3 4 5 6 7 8 9 10 11 12
|
template <typename T>
void BST<T>::insert(T &p) {
if (root != nullptr) {
}
else {
Node<T> *newNode = new Node<T>;
newNode->data = new Packet(p);
root = newNode;
cout << root->data->getDescription() << endl;
}
}
|
This is from your second version posted above. Notice "new Packet( p )".
I didn't think of this before, by what is "Packet"? Is that not "T". That should have read "new T( p )".
That said, the real point here is that "new T( p )" invokes what appears to be a copy constructor. So, this copies anyway.
JLB's code copies, but does not have the additional workload of allocating a "new" P to do it.
At this time, I want to avoid using smart pointers. I don't have an extensive history with them and I'm more comfortable with manual pointers. I'd like to keep it like that just for now but possible in the future, an investigation into this may be on the cards.
|
That has been the history of smart pointers for most early C++ programmers (before smart pointers and templates existed). I can't say it makes sense to me.
Contemplate what a node is. Did you ever stop to think it is a specialized type of smart pointer? Nodes hold objects in various ways (they're a loosely defined concept). As you've implemented Node, storing via pointer, you've created an object which holds a pointer and (at least should) deletes it when the node falls from scope (or is deleted). That's what smart pointers do.
How does a node give you the data? If you sequence through the container, you ultimately require access to the data the user put into the container. Usually that comes from an iterator. An iterator is a kind of pointer into the container. A kind of smart pointer.
The only difference is that smart pointers are not used as links in containers (those which are based on links), or iterators. Well, that and some small interface to get to the data.
I say again, the use of smart pointers is one of the most important aspects of C++. It is central to modern writing. You're already about 40% into writing something that does what smart pointers do, just not called smart pointers because they are intended for something else (links).
In my view, a C++ programmer without smart pointers is a fundamental contradiction. They're simple, easy to learn, save a lot of bugs (you have no idea just how much, I'm sure...but some 30% of ALL bugs from C or pre-98 C++ were associated with raw pointers and related memory management).
Think of that for a moment. A good portion of the reliability of what you're now building will be on the point of memory control. I can't see logic in avoiding a tool so fundamentally aimed a memory control.
No doubt, there are plenty of times we must write with raw memory management. There can be no way around it under certain circumstances. The most natural response a C++ developer has to such situations is to encapsulate the "nastiness" of that, get it seriously well tested and debugged, and close up tightly so no one else has to ever deal with it.
That's what smart pointer do for all dynamically allocated instances of objects. Containers, like the one you're building, do that for collections of objects.
If I lose you on everything else, the one, single, most important thing any C++ programmer should learn post 2010 is how to use smart pointers, which would take maybe two sessions of about 2 hours each, soup to nuts. There is just not that much about them to learn.
How does @JLBorges version allow the user to store via. pointer? I'm having a hard time finding where data is initiated, taking in packet.
|
JLB's code does not explicate the usage of pointers. Like the standard containers, it takes no account of pointers, but also does nothing to prevent them.
1 2 3 4 5
|
bool insert( const T& v ) {
if( root != nullptr ) return root->insert( v, cmp ) ;
else return bool( root = new node{v} ) ;
}
|
If "T" is "Packet *" and not "Packet", then "Insert" will require a pointer, which makes "v" and reference to a Packet *, and Node stores such a pointer initialized with "new node{v}". Like the standard containers, this would mean calling code must provide a pointer, and perhaps both allocation and deletion (it's uncomfortable with the standard containers, too...unless they don't own what they point to).
Now, consider your code:
1 2 3 4 5 6 7 8 9 10 11
|
void BST<T>::insert(T &p) {
if (root != nullptr) {
}
else {
Node<T> *newNode = new Node<T>;
newNode->data = new Packet(p);
root = newNode;
cout << root->data->getDescription() << endl;
}
}
|
Could you prevent the user from providing "Packet *" as the type for "T".
Since I suspect "new Packet( p )" is an error, and that should be new "T( p )", what would that mean if T is a "Packet *", not a "Packet"?
This is long for a post by now, and I'm changing directions for the evening...I'll consider a simplified example for you in a while. In the meantime, think upon these points and we'll continue later.