I currently have an class grounds which is used to make objects for all the blocks that make up the ground for a game I am making. What is the best way to keep track of this somewhat large list of blocks? I know how to keep track of objects in python but I recently moved to C++ and I am unsure of how to go about setting up some sort of list that is easy to iterate through.
In C++, the standard library (also referred to as the standard template library) provides several container classes that store a collection of things. The "things" may be any data type, including fundamental and user-defined.
Which container to use depends on your needs. Here's an authoritative article on it from Microsoft.
Your best bet is to use either vector if you need the ability to refer to specific elements by their position in your container, or a set if the order of elements doesn't matter and you need to quickly be able to check whether a certain element is present.
Some examples:
vector<MyClass> mycontainer; // a vector that holds objects of type MyClass
MyClass myObj;
mycontainer.push_back(myObj);
cout << mycontainer[0] << endl; // equivalent to cout << myObj << endl;
Or using a set:
set<MyClass> mycontainer;
MyClass myObj;
mycontainer.insert(myObj);
if (mycontainer.find(myObj))
cout << "Yep, myObj is in the set." << endl;
The reason there's no one ultimate container is that there are efficiency tradeoffs. One container may be blazing-fast at identifying whether an element is present within it, while another is optimal for removing an arbitrary element, etc.
So your best bet is to consider what behaviors you want your container to support (and how efficiently!), and then to review the authoritative article I linked to earlier.
Related
I'm curious about the answer to this question as I mostly work with containers.
which one is more logical to use in minimum of 100 (and maximum of 10k) elements in vector or map container in?
std:::vector<std::unique_ptr<(struct or class name)>>
std:::vector<std::shared_ptr<(struct or class name)>>
std:::vector<(struct or class name)*>
Machine detais: FreeBSD 12.1 + clang-devel or gcc11.
This is really opinion-based, but I'll describe the rules of thumb I use.
std:::vector<(struct or class name)> is my default unless I have specific requirements that are not met by that option. More specifically, it is my go-to option UNLESS at least one of the following conditions are true;
struct or class name is polymorphic and instances of classes derived from struct or class name need to be stored in the vector.
struct or class name does not comply with the rule of three (before C++11), the rule of five (from C++11), OR the rule of zero
there are SPECIFIC requirements to dynamically manage lifetime of instances of struct or class name
The above criteria amount to "use std::vector<(struct or class name)> if struct or class name meets requirements to be an element of a standard container".
If struct or class name is polymorphic AND there is a requirement that the vector contain instances of derived classes my default choice is std:::vector<std::unique_ptr<(struct or class name)> >. i.e. none of the options mentioned in the question.
I will only go past that choice if there are special requirements for managing lifetime of the objects in the vector that aren't met by either std:::vector<(struct or class name)> or std:::vector<std::unique_ptr<(struct or class name)> >.
Practically, the above meets the vast majority of real-world needs.
If there is a need for two unrelated pieces of code to have control over the lifetime of objects stored in a vector then (and only then) I will consider std:::vector<std::shared_ptr<(struct or class name)> >. The premise is that there will be some code that doesn't have access to our vector, but has access to its elements via (for example) being passed a std::shared_ptr<(struct or class name)>.
Now, I get to the case which is VERY rare in my experience - where there are requirements to manage lifetime of objects that aren't properly handled by std:::vector<(struct or class name)>, std:::vector<std::unique_ptr<(struct or class name)> >, or by std:::vector<std::shared_ptr<(struct or class name)> >.
In that case, and only that case, I will - and only if I'm desperate - use std:::vector<(struct or class name)*>. This is the situation to be avoided, as much as possible. To give you an idea of how bad I think this option is, I've been known to change other system-level requirements in a quest to avoid this option. The reason I avoid this option like the plague is that it becomes necessary to write and debug EVERY bit of code that explicitly manages the lifetime of each struct or class name. This includes writing new expressions everywhere, ensuring every new expression is eventually matched by a corresponding delete expression. This option also means there is a need to debug hand-written code to ensure no object is deleted twice (undefined behaviour) and every object is deleted once (i.e. avoid leaks). In other words, this option involves lots of effort and - in non-trivial situations - is really hard to get working correctly.
Start with correct behavior, not performance.
Does your container own your objects? If no, use raw pointers. If yes, use smart pointers. But which ones? See below.
Do you need to support several containers containing the same object, and is it unclear which container will be deleted first? If the answer to both is "yes", use shared_ptr. Otherwise, use unique_ptr.
Later, if you discover that accessing the smart pointers wastes too much time (unlikely), replace the smart pointers by raw pointers together with highly optimized memory management, which you will have to implement according to your specific needs.
As noted in comments, you could do it without pointers. So, before applying this answer, ask yourself why you need pointers at all (I guess the answer is polymorphism, but not sure).
It's hard to provide a firm solution to your question without seeing the context and the way your struct/class operates.
But I still want to provide some basic info about smart pointers so hopefully, you can make a wise decision.
An example:
#include <iostream>
#include <vector>
#include <memory>
int main( )
{
struct MyStruct
{
int a;
double b;
};
std::cout << "Size of unique_ptr: " << sizeof( std::unique_ptr< MyStruct > ) << '\n';
std::cout << "Size of shared_ptr: " << sizeof( std::shared_ptr< MyStruct > ) << '\n';
std::cout << '\n';
std::vector< std::unique_ptr<MyStruct> > vec1; // a container holding unique pointers
std::vector< MyStruct* > vec2; // another container holding raw pointers
vec1.emplace_back( std::make_unique<MyStruct>(2, 3.6) ); // deletion process automatically handled
vec2.emplace_back( new MyStruct(5, 11.2) ); // you'll have to manually delete all objects later
std::cout << vec1[0]->a << ' ' << vec1[0]->b << '\n';
std::cout << vec2[0]->a << ' ' << vec2[0]->b << '\n';
}
The possible output:
Size of unique_ptr: 8
Size of shared_ptr: 16
2 3.6
5 11.2
Check the assembly output here and compare the two containers. As I saw, they generate the exact same code.
The unique_ptr is very fast. I don't think it has any overhead. However, the shared_ptr has a bit of overhead due to its reference counting mechanism. But it still might be more efficient than a handwritten reference counting system. Don't underestimate the facilities provided in the STL. Use them in most cases except the ones in which STL does not exactly perform the specific task you need.
Speaking of performance, std::vector<(struct or class name)> is better in most cases since all the objects are stored in a contiguous block of heap memory, and also dereferencing them is not required.
However, when using a container of pointers, your objects will be scattered around heap memory and your program will be less cache-friendly.
I'm afraid that standard library containers store inside themselves copies of all elements that I push into them. I hoped that they worked with references or pointers to my elements, so they don't waste extra memory and time making copies of each element. I made this proof:
queue<int> prueba;
int x = 5;
prueba.push(x);
x++;
cout << prueba.front() << ", ";
cout << x;
prueba.pop();
And the result was: 5, 6.
So, If I make a big class with a lot of heavy members, and then, I push a lot of objects of that class into a standard library container.
Will containers make a copy of each object inside? That's terrible!
Is there any way to avoid this catastrophic end, other than create just containers of pointers?
Does STL structures stores copies or references?
C++ standard containers are non-instrusive containers and as such they have the following properties:
Object doesn't "know" and contain details about the container in which is to be stored. Example:
struct Node
{
T data;
}
1. Pros:
does not containe additional information regarding the container integration.
object's lifetime managed by the container. (less complex.)
2. Cons:
store copies of values passed by the user. (inplace emplace construction possible.)
an object can belong only to one container. (or the contaier should store pointers to objects.)
overhead on storing copies. (bookkeeping on each allocation.)
can't store derived object and still maintain its original type. (slicing - looses polymorphism.)
Thus, the answer to your question is - they store copies.
Is there any way to avoid this catastrophic end, other than create just containers of pointers?
As far as I know, a reasonable solution is container of smart pointers.
The answer to your question is simple: STL containers store copies.
I am new to shared_ptr from boost and am considering to iterate over my set to get the best object.
EDIT: added information about first_world
std::set<World::CPtr> first_world = ... // long call, but it gets a set of constant shared pointers to the class World, where various methods exist
typedef boost::shared_ptr<World const> CPtr;
World::CPtr best = *(first_world.begin());
for (World::CPtr lo : first_world) {
if (best->getValue() >= lo->getValue() ){
best = lo;
}
}
Later I want to use that shared pointer, My program crashes with communicate that Assertion `px != 0' failed. I followed the rules from here, I mean I used a shared pointer as iterator in a loop but then I assign it to another pointer. Is that bad practice, is there better practice?
cout << "name is: " << best->getDefinition() << endl;
Nothing's blatantly wrong in what's pasted there, so there's probably going to be a mistake in the long call that creates the set.
For example, it would be easy to mess this up if raw pointers are involved when adding elements to the set. Consider this situation, a concrete illustration of a common mistake that's sort of alluded to in your Best Practices link:
std::set<World::CPtr> first_world;
World* pWorld = new World();
// Bad:
first_world.insert(World::CPtr(pWorld));
first_world.insert(World::CPtr(pWorld));
// Oops!! You now have two independently refcounted entries in first_world!
// emplace is just as deadly, but more subtle.
// Now you'll have three shared pointers in your set:
first_world.emplace(pWorld);
If you look through your entries in first_world and see duplicates then you'll know you're in trouble. To avoid mistakes like this, make sure you only construct shared_ptrs from other shared_ptrs (or boost::make_shared).
So that's tip #1: Avoid constructing shared_ptrs from a raw pointers. (That includes the this pointer if Worlds are adding themselves to your set... if you're doing that, better start googling enable_shared_from_this).
Now let's follow that guideline to get expected behavior:
std::set<World::CPtr> first_world;
World::CPtr spWorld1 = boost::make_shared<World>();
World::CPtr spWorld2{spWorld1};
first_world.insert(spWorld1);
first_world.insert(spWorld2);
// Just one element in first_world now, as expected.
Finally, a few (somewhat unrelated) suggestions:
std::set as you've declared it is only looking at the address of World objects on the heap when it compares entries. So if you have two different Worlds on the heap that are logically identical then they'll both have distinct entries in the set. Is that your intent? You'll need to plug in your own custom compare function (std::set's second template argument) to do a deep comparison of Worlds if you want to avoid logical duplicates.
Check to make sure that first_world isn't empty before looking for the max, otherwise bad things will happen.
Standard algorithms are your friend! Consider using the std::max_element algorithm instead of a raw loop. (This makes it easier for other people to reason about what you're doing with a quick glance).
I have a set of small objects. Each of these objects points to other objects. These pointers might be realized as actual pointers or as index into an array of the objects or something else. It might be an array of such pointers whose length might change. There might be pointers to objects of the same type and to other types, but this is known at compile time.
So, for example: I have a class Person. This person has two pointers to its parent Persons. There's another class Place. Each Person has a list of pointers to all Places he/she has visited.
In contrast to an actual family tree, I might want to change the tree from time to time by deleting/inserting some Persons.
Is there a container in the C++ Standard Library (C++ 11) for that purpose or should I better look for a dedicated memory management class?
I will have to pass the data to a C interface why I would prefer a storage method which is based on an accessible (read only) linear array.
Sounds like a great time to quote Stepanov:
Use vectors whenever you can. If you cannot use vectors, redesign your solution so that you can use vectors.
The "accessible linear array" part points to vector<Person> - none of the other containers have that feature - and the rest of your use-case doesn't suggest any specific kind storage or access. Part of it sounds like it might be cleaner if you could do vector<shared_ptr<Person>> but that would break your C interface requirement. So vector<Person> is probably your answer.
Questions:
"There might be pointers to objects of the same type and to other types, but this is known at compile time."
"These pointers might be realized as actual pointers or as index into an array of the objects or something else."
In contrast to an actual family tree, I might want to change the tree from time to time by deleting/inserting some Persons.
"Is there a container in the C++ Standard Library (C++ 11) for that purpose or should I better look for a dedicated memory management class?"
"I will have to pass the data to a C interface why I would prefer a storage method which is based on an accessible (read only) linear array."
Answers:
This could become difficult if you want to use pointers to multiple types of objects in a single container. But you could make either a raw array or a std::vector work.
If you're just using indices that would greatly simplify your "pointers to multiple types" problem. Again either a raw array or a std::vector work.
Dynamically changing raw array sizes gets sketchy fast, I'd say this is a point for std::vector.
Depending upon the time that you are willing to put in, managing your memory is a tremendous endeavor, I'd stick with a raw array or std::vector until they pried my cold dead fingers loose.
If you have C++11 using std::vector::data can make a std::vector just as usable as a raw array here, if not this would be simpler to implement as a raw array.
std::vector has numerous benefits to you as the programmer. Not the least of which is automatic memory management. So I'd lean toward std::vector where it is an option.
I prefer to use vector rather than other (list, etc) . as Bjarne said "If you know int and vector, so you know C++".
Here is the link at Youtube, as Bjarne said about vector:
Bjarne Stroustrup: Why you should avoid Linked Lists
I have a class that has a member of type std::vector. In some places I need the size of that vector in another class. Because the member is private, I have created a getter to return it. When reviewing the code a question came out in my mind: Is it better to call the getter and then it's size() or is it good to create a "size getter" instead?
Here is my class:
class MyClass
{
private:
std::vector< int > m_myVec;
public:
std::vector< int > getMyVec() const { return m_myVec; }
// Shall I create:
// std::size_t getMyVecSize() const { return m_myVec.size(); }
// ... other function
};
In some other part of the code I do:
std::size_t sz = myClsObj.getMyVec().size(); // or
if (myClsObj.getMyVec().size() > 5) { /*...*/ }
Is it a good practice to do so, or I shall create and call the "size getter" instead?
I need both the vector (in other parts of the code I call the getter) and its size; so there is no point to choose to keep just one of the getters.
Another fact is that I am using C++11, so there is no need to return a const reference.
Based on the C++11: Is it so smart not to return the vector but its size if I call myClsObj.getMyVec().size()?
You can refer to the Tell Don't Ask principle. It may be a bit confusing here, as both version are technically "asking" for something. But the point is not to use getters to retrieve implementation details of a class and then perform some operations on it, but to tell the class to do the required work, which is in this case - retrieving the size.
This is also related to the Law of Demeter. The approach with returning the whole vector is visualized in this link in an awesome way, with the following story:
[...] “that’ll be $1.95.” At this point, naturally, I removed my pants and the guy started screaming at me about police and indecent exposure. Confused, I said, “look, I’m just trying to pay you — I’ll hand you my pants and you go rummaging around in my pockets until you find my wallet, which you’ll take out and go looking through for cash.
The "size getter" method relates to a more natural way, of getting your wallet yourself from your pants and paying :-)
It is also comes directly from one of the most basic concepts in OOP - Encapsulation. Briefly, its point is to hide (encapsulate) as much details of class's implementation from the outside world. Less coupling gives you more flexibility in the future. Don't worry if this sounds too abstract or hazy. Every programmer (i.e. almost every programmer I've met, including me) eventually came to a point, when each supposedly simple change, had to be followed by an avalanche of fixes in distant parts of code. Felling the revenge of coupling under your fingers makes you recall this rule, and remember it forever ;)
And finally, usually you don't create classes that represent a wrapped vector or something similar. vector is just a technicality. Usually such a class represents a collection of some particular elements that have name on the level of your Domain logic. So most of the time it's not .getTheSizeOfMyInnerVector but rather .getRecordCount or .getNumberOfStudents etc. Clients of such classes don't even need to know that there is a std::vector inside. It doesn't matter, as long as the class handles its task for maintaining a collection of something. The aforementioned flexibility can for example mean in this case, that you can switch to a different container without worrying about the clients of your class. And without riffling through possibly thousands of places where this class is being used in your code.
Make a "size getter" and return the value of m_myVec.size() unless you actually need complete access to the vector. The size getter would expose less of your code to the outside world. If you're just going to provide a method to get the vector it's essentially not private at all.
Well, first of all, as commenters have pointed out, IF you use a getter for the vector, make it return a const reference instead of a copy.
To answer your question: It depends on what level of data encapsulation you want. If the vector itself is an implementation detail of the class, and you do not want users of the class to be able to change its contents (or only through well defined operations in the class contract), you should not have a getter for (a reference to) the vector.