im trying to archieve the following in c++:
I want to be able to create local variables, add them to a global static vector and only pointers to them should be added to the vector.
In C# i was able to write (example):
public static List<Component> CACHE = new List<Component>(); //Somewere in class
//Now in method:
Component a = new Component();
a.Name = "Noël";
CACHE.Add(a); //Adds reference to CACHE a without copy
in c++ i see 2 solutions:
1.Use dynamic allocations:
static std::vector<Component*> CACHE; //Somewere in class
//Now in method:
Component* a = new Component();
a->Name = L"Noël";
CACHE.push_back(a);
the problem is that i dont want to use dynamic allocation because its slow.
2.My idea:
(Somehow i have to make the new operator private or just say in the documentation never use new on Component)
//somewere hidden:
std::vector<Component*> GLOBAL_CACHE;
//In method dont use new, instead we use a custom global function
Component* a = CREATE_COMPONENT();
static std::vector<Component*> CACHE; //Example
Component& ExampleRef;//Example
a->Name = L"Noël";
CACHE.push_back(a);
ExampleRef = *a;
and now CREATE_COMPONENT():
Component* CREATE_COMPONENT()
{
GLOBAL_CACHE.push_back(Component()); //Add empty component
return &GLOBAL_CACHE[GLOBAL_CACHE.size() - 1]; //return pointer to construct added above. I think we now have everything on the stack and we just send around pointers to the stack object
}
Is my idea worth it or even working? Or should i just use dynamic allocation?
Doing the same in C++ is not possible because of garbage collection. But you can do it similarly by using shared_ptr<Component> as the element type of your vector:
#include <memory>
std::vector<std::shared_ptr<Component>> CACHE;
// ...
auto a = std::make_shared<Component>();
a->Name = "Noël";
CACHE.push_back(a);
The Component will be automatically destroyed when there's no more references to it.
If you don't intend to store copies of the pointers somewhere else, but CACHE is the only place where you put them, then you can use unique_ptr instead:
#include <memory>
std::vector<std::unique_ptr<Component>> CACHE;
// ...
CACHE.push_back(std::make_unique<Component>());
CACHE.back()->Name = "Noël";
Unlike shared_ptr, unique_ptr can not be copied, only moved, meaning there can only ever be 1 reference to it. The Component object will be automatically destroyed when the unique_ptr is destroyed.
This is using memory allocation, but the same it true for C#.
Note that, unlike C#, using new and delete in C++ is a bad idea because they're prone to resource and memory leaks. Use shared_ptr and unique_ptr instead if you want to create objects on the heap.
Finally, you should read up on "C++ move semantics". You don't need to avoid putting things on the stack. You can move objects instead of copy them. Example:
#include <memory>
std::vector<Component> CACHE;
// ...
Component a;
a.Name = "Noël";
CACHE.push_back(std::move(a)); // No copy. The 'a' variable can no longer be used.
Moves are sometimes automatic and they are a big part of C++. But you need to educate yourself about it.
Related
I've seen many sites talking about the correct way to implement a d'tor for a class that holds a map.
But not for the case where the values of the map themselves are dynamically allocated.
For example, let Manager be a class which hold map<int, User*> where User is some class which I'll allocate dynamically later.
By the rules of the exercise, it should handle a registerUser(string name) function, which creates a new User instance and adds it to the map.
Something like:
User* registerUser(std::string userName) {
User* pNewUser = new User(userName);
// Setting some stuff
auto ret = users.insert(std::pair<int, User*>(pNewUser->id, pNewUser));
// Finishing and returning a pointer to the new allocated User
}
AND TO THE QUESTION ITSELF:
Should the d'tor do something special beyond users.clear()?
Will the memory be freed successfully or shall I iterate over the elements and delete them?
Thank you in advance :)
Don't use pointers when you do not have to. The std::map already manages the lifetime of its elements for you:
struct User {
std::string name;
int id;
static int id_counter;
User(const std::string& name) : name(name),id(id_counter++) {}
};
struct manager {
std::map<int,User> users;
User& registerUser(std::string userName) {
User u(userName);
auto ret = users.emplace(u.id,u);
return ret.first->second;
}
};
If you are forced to use a std::map<int,User*> because of weird unrealistic exercise requirements (or because the map is supposed to hold polymorphic objects) and you cannot use smart pointers then you need to delete what you newed. The map only manages its elements, not what they might point to:
struct manager {
std::map<int,User*> users;
User& registerUser(std::string userName) {
User* u = new User(userName);
auto ret = users.emplace(u->id,u);
return *(ret.first->second);
}
~manager() {
for (const auto& user : users){
delete user.second;
}
}
// the compiler generated assignment and copy would not do the right thing
manager(const manager&) = delete;
manager& operator=(const manager&) = delete;
};
Not sure where you read about holding a map as member and needing to call clear(). That is non-sense. The map has a destructor that is called automatically and the map does already clean up after itself.
Last but not least, you need to read about the rule of 3 (What is The Rule of Three?), because a destructor alone is not sufficient to correctly manage raw pointers as members. As mentioned in a comment, when you copy the manager via the compiler generated copy constructor or assignment, bad things will happen. Note that this isnt the case with the first version above. When possible you should try to follow the rule of 0 (https://en.cppreference.com/w/cpp/language/rule_of_three scroll down).
Should the d'tor do something special beyond users.clear()?
In general that depends on how your code handles ownership of heap allocated objects; any time you call a constructor by new (aka allocate on the heap) you should be aware of wich component in your code takes ownership over the newly created object and in consequence is responsible for deletion of the object.
For this specific toyproblem your Manager class should also handle the deletion of the object by iterating over all elements in your favourite way and calling delete. Be aware some other component could still hold onto one of these User-pointers wich will cause a crash by accessing invalid memory in the best case and running fine until it shipped in the worst case (or starting a nuclear war, since this is in the scope of undefined behaviour). The state of the art solution is using some kind of smart pointer.
Of course as 463035818_is_not_a_number put it so nicely in his answer you don't need to call users.clear(). Since the map will be deleted automagically since it is a statically allocated variable (but not necessarily the contents of the map).
Consider a simple class:
class MyInt {
public:
MyInt();
MyInt(const char *num);
};
I want to intergrate reference counting design pattern in to the class, which means i need to keep track of how much pointers point to an instance of this class. I need to implement it in this class only or create a different class and inherit it.
Given this example code i want to clear any allocated memory of the program:
int main() {
MyInt*a = new MyInt("10");
a = new MyInt("20");
delete a;
return 0;
}
My Tries
I tried operator oveloading of '=' and adding referenceCount member:
MyInt &MyInt::operator=(const MyInt* right) {
MyInt*left = this;
*this = right;
left->referenceCount -= 1;
if (left->referenceCount == 0) {
delete (left);
}
return *this;
}
But this does not work because we assign pointer of the class to another pointer.
Also tried to override the new and delete operators but can't seem to make it work and keep track of the number of pointer to an instance.
As it seems i need to implement four things: copy constructor, operator new, operator delete and operator =.
How can i effectivly keep track of the pointers and clear unpointed memory automaticly?
std::shared_ptr does exactly this. From the ref:
Manages the storage of a pointer, providing a limited
garbage-collection facility, possibly sharing that management with
other objects. [...] Once all shared_ptr objects that share ownership
over a pointer have released this ownership, the managed object is
deleted.
so I suggest you use this instead.
a is a pointer, so assigning to a will not involve MyInt::opterator= in any way. There is no way to detect when a pointer to T is assigned to by overloading T's operators. To do this, you would need to design a class type that behaves like a pointer. Then you could properly track when the pointer might leak an object and properly delete it. Fortunately for you, the standard library already provides this class. It's std::shared_ptr. Here is your example modified to use std::shared_ptr :
#include <memory>
struct InfInt {
InfInt(const char *) {}
};
int main()
{
auto a = std::make_shared<InfInt>("10");
a = std::make_shared<InfInt>("20"); // the previous `a` is deleted
// The object pointed to by `a` is automatically deleted when
// the last reference to it goes out of scope
return 0;
}
I have a question about good C++ style:
I would like to write a class "MyClass" which has one or some pointers as members and MyClass is able to allocate memory to this pointers. I would like to use the implicit give default-copy-constructor (as well as the default-assignement-operator) to copy an instance of MyClass, so that only the pointers were copied and the new object share the data which the initial object has allocated.
My idea was to prohibit copied objects (created with copy constructor or assignment operator) to release memory (as well as allocate memory to member pointers). In order to distinguesh between copied objects and original objects (created by the constructor), I want to use the following code:
class MyClass
{
public:
MyClass(): originalPtr(this) { data = new char[100000]; }
~MyClass() { if(originalPtr == this) delete[] data; }
private:
MyClass *originalPtr;
char *data; // shared data (not copiable)
char otherFeatures[10]; // individual data (copiable)
};
Would this solution (using the comparison with the this-pointer) a good style for such a purpose (e.g. parsing an object by call by value) or is it risky? Of course, I assume that the original object live always longer than the copied objects.
Thank you!
No, this is a bad idea. If the pointers are shared by several instances, than the one to deallocate should be the last one to die, not the original one. This differs in the sense that the original one might not be the one to die, which would cause all others to be pointing at garbage. Even though you assume that it's the last one to die, you need to realise that the inner workings of a class should not rely on external assumptions. That is, the class has no guarantees on how its life span is managed by the rest of the implementation, so it shouldn't make assumptions.
In this situation you should track references to your data. The basic idea is to keep track of how many copies of the class you have. As soon as that count reaches zero, you are free to release that memory; the last copy has just died. Fortunately for you, STL already provides such an implementation. These are known as Smart Pointers. There are others, such as std::unique_ptr, which makes the opposite by ensuring that the data is owned only by a single instance.
Ok, assuming the general case, where the original object does not die at last. I like the idea to just count the instances. For example one could use such a concept:
class MyClass
{
public:
MyClass(): countOfInstances(new int())
{
++*countOfInstances;
data = new char[100000];
}
~MyClass()
{
--*countOfInstances;
if(!countOfInstances)
{
delete[] data;
delete countOfInstances;
}
}
MyClass(const MyClass &other) // analogous for the assignment operator
{
countOfInstances = other.countOfInstances;
data = other.data;
otherFeatures = other.otherFeatures;
++*countOfInstances;
}
private:
int *countOfInstances;
char *data; // shared data (not copiable)
char otherFeatures; // individual data (copiable)
};
Here, one should also make sure that the shared memory is completely allocated before allowing to make copies.
I have a singleton class that holds a vector with data. My problem is that I want to add data to that vector using the standard push_back() method. I have an object I want to save in that vector but it's a local object (created in a method in another class). Obviously, at the end of this method the local variable would be deleted which is fine because I do a push_back() of that data to the vector.
Now, this works fine for as long the method didn't end. After it ends the data is gone. This seems weird because push_back() should be using the copy constructor right? Now, I tried to add the local variable to the vector by reference, by value, as a pointer and with the move constructor in C++11 but all those things don't seem to work.
So this is the setup of the problem class-wise:
ConnectionManager (holds the vector)
ClassA (which has a method with the local typeX object)
So, in short, I want the object created in a method in ClassA to be available after that method but in the vector from the ConnectionManager class.
EDIT: Here's the typeX I'm talking about:
struct Connection
{
SOCKET socket;
PlayerData* pPlayerData;
};
socket is just your normal winsock SOCKET variable and PlayerData* is a custom object created with Google's ProtocolBuffer.
FURTHER EDIT:
This is how I create the data:
Predefined::Connection connTemp;
connTemp.socket = 0;
connTemp.pPlayerData = data;
MultiplayerData::GetInstance()->AddPlayerToGame(connTemp);
connTemp.pPlayerData is, to answer the question, a locally created variable but it's created as a pointer.
If the issue is that you're creating the PlayerData data, and expecting to have the same data be still available after the function exits, it looks like you should use a type such as std::shared_ptr<PlayerData> instead of a naked PlayerData*.
#include <vector>
#include <memory>
//..
class PlayerData
{
int x, y, z;
public:
PlayerData(int a1, int a2, int a3) : x(a1), y(a2), z(a3) {}
};
typedef std::shared_ptr<PlayerData> PlayerDataPtr;
struct Connection
{
SOCKET socket;
PlayerDataPtr pPlayerData;
};
typedef std::vector<Connection> ConnectionVector;
void foo()
{
auto data = std::make_shared<PlayerData>(1, 2, 3); // create data dynamically
//...
Connection connTemp;
connTemp.socket = 0;
connTemp.pPlayerData = data;
MultiplayerData::GetInstance()->AddPlayerToGame(connTemp); // this does the push_back
//...
}
Since pPlayerData is now a shared_ptr, those copies that vector will generate just bump up a reference count, and conversely, when those copies are destroyed, the reference count is decremented. When the reference count reaches 0, then the data will indeed be deleted.
If you haven't called reset on the shared pointer, this is more or less, your guarantee that the data you created before the push_back was done will exist, as long as that entry in the vector wasn't removed.
Also, I edited the example to show a simpler PlayerData class. Note how make_shared is used.
Struct Connection will indeed be copied into the vector, so you don't need to worry about end of its lifetime. pPlayerData however needs to point into a memory allocated with new and owned by somebody.
connTemp.pPlayerData = data;
Where does the 'data' come from - generated locally?
The 'data' needs to be allocated by 'new' at some point.
If the "data" are all unique, consider using auto_ptr or unique_ptr for the type of pPlayerData member - C++ doesn't automatically manage standard pointers. If they're not unique, use shared_ptr or intrusive_ptr - can start with shared and retrofit intrusive later.
Hi I asked a question today about How to insert different types of objects in the same vector array and my code in that question was
gate* G[1000];
G[0] = new ANDgate() ;
G[1] = new ORgate;
//gate is a class inherited by ANDgate and ORgate classes
class gate
{
.....
......
virtual void Run()
{ //A virtual function
}
};
class ANDgate :public gate
{.....
.......
void Run()
{
//AND version of Run
}
};
class ORgate :public gate
{.....
.......
void Run()
{
//OR version of Run
}
};
//Running the simulator using overloading concept
for(...;...;..)
{
G[i]->Run() ; //will run perfectly the right Run for the right Gate type
}
and I wanted to use vectors so someone wrote that I should do that :
std::vector<gate*> G;
G.push_back(new ANDgate);
G.push_back(new ORgate);
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
but then he and many others suggested that I would better use Boost pointer containers
or shared_ptr. I have spent the last 3 hours reading about this topic, but the documentation seems pretty advanced to me . ****Can anyone give me a small code example of shared_ptr usage and why they suggested using shared_ptr. Also are there other types like ptr_vector, ptr_list and ptr_deque** **
Edit1: I have read a code example too that included:
typedef boost::shared_ptr<Foo> FooPtr;
.......
int main()
{
std::vector<FooPtr> foo_vector;
........
FooPtr foo_ptr( new Foo( 2 ) );
foo_vector.push_back( foo_ptr );
...........
}
And I don't understand the syntax!
Using a vector of shared_ptr removes the possibility of leaking memory because you forgot to walk the vector and call delete on each element. Let's walk through a slightly modified version of the example line-by-line.
typedef boost::shared_ptr<gate> gate_ptr;
Create an alias for the shared pointer type. This avoids the ugliness in the C++ language that results from typing std::vector<boost::shared_ptr<gate> > and forgetting the space between the closing greater-than signs.
std::vector<gate_ptr> vec;
Creates an empty vector of boost::shared_ptr<gate> objects.
gate_ptr ptr(new ANDgate);
Allocate a new ANDgate instance and store it into a shared_ptr. The reason for doing this separately is to prevent a problem that can occur if an operation throws. This isn't possible in this example. The Boost shared_ptr "Best Practices" explain why it is a best practice to allocate into a free-standing object instead of a temporary.
vec.push_back(ptr);
This creates a new shared pointer in the vector and copies ptr into it. The reference counting in the guts of shared_ptr ensures that the allocated object inside of ptr is safely transferred into the vector.
What is not explained is that the destructor for shared_ptr<gate> ensures that the allocated memory is deleted. This is where the memory leak is avoided. The destructor for std::vector<T> ensures that the destructor for T is called for every element stored in the vector. However, the destructor for a pointer (e.g., gate*) does not delete the memory that you had allocated. That is what you are trying to avoid by using shared_ptr or ptr_vector.
I will add that one of the important things about shared_ptr's is to only ever construct them with the following syntax:
shared_ptr<Type>(new Type(...));
This way, the "real" pointer to Type is anonymous to your scope, and held only by the shared pointer. Thus it will be impossible for you to accidentally use this "real" pointer. In other words, never do this:
Type* t_ptr = new Type(...);
shared_ptr<Type> t_sptr ptrT(t_ptr);
//t_ptr is still hanging around! Don't use it!
Although this will work, you now have a Type* pointer (t_ptr) in your function which lives outside the shared pointer. It's dangerous to use t_ptr anywhere, because you never know when the shared pointer which holds it may destruct it, and you'll segfault.
Same goes for pointers returned to you by other classes. If a class you didn't write hands you a pointer, it's generally not safe to just put it in a shared_ptr. Not unless you're sure that the class is no longer using that object. Because if you do put it in a shared_ptr, and it falls out of scope, the object will get freed when the class may still need it.
Learning to use smart pointers is in my opinion one of the most important steps to become a competent C++ programmer. As you know whenever you new an object at some point you want to delete it.
One issue that arise is that with exceptions it can be very hard to make sure a object is always released just once in all possible execution paths.
This is the reason for RAII: http://en.wikipedia.org/wiki/RAII
Making a helper class with purpose of making sure that an object always deleted once in all execution paths.
Example of a class like this is: std::auto_ptr
But sometimes you like to share objects with other. It should only be deleted when none uses it anymore.
In order to help with that reference counting strategies have been developed but you still need to remember addref and release ref manually. In essence this is the same problem as new/delete.
That's why boost has developed boost::shared_ptr, it's reference counting smart pointer so you can share objects and not leak memory unintentionally.
With the addition of C++ tr1 this is now added to the c++ standard as well but its named std::tr1::shared_ptr<>.
I recommend using the standard shared pointer if possible. ptr_list, ptr_dequeue and so are IIRC specialized containers for pointer types. I ignore them for now.
So we can start from your example:
std::vector<gate*> G;
G.push_back(new ANDgate);
G.push_back(new ORgate);
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
The problem here is now that whenever G goes out scope we leak the 2 objects added to G. Let's rewrite it to use std::tr1::shared_ptr
// Remember to include <memory> for shared_ptr
// First do an alias for std::tr1::shared_ptr<gate> so we don't have to
// type that in every place. Call it gate_ptr. This is what typedef does.
typedef std::tr1::shared_ptr<gate> gate_ptr;
// gate_ptr is now our "smart" pointer. So let's make a vector out of it.
std::vector<gate_ptr> G;
// these smart_ptrs can't be implicitly created from gate* we have to be explicit about it
// gate_ptr (new ANDgate), it's a good thing:
G.push_back(gate_ptr (new ANDgate));
G.push_back(gate_ptr (new ORgate));
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
When G goes out of scope the memory is automatically reclaimed.
As an exercise which I plagued newcomers in my team with is asking them to write their own smart pointer class. Then after you are done discard the class immedietly and never use it again. Hopefully you acquired crucial knowledge on how a smart pointer works under the hood. There's no magic really.
The boost documentation provides a pretty good start example:
shared_ptr example (it's actually about a vector of smart pointers) or
shared_ptr doc
The following answer by Johannes Schaub explains the boost smart pointers pretty well:
smart pointers explained
The idea behind(in as few words as possible) ptr_vector is that it handles the deallocation of memory behind the stored pointers for you: let's say you have a vector of pointers as in your example. When quitting the application or leaving the scope in which the vector is defined you'll have to clean up after yourself(you've dynamically allocated ANDgate and ORgate) but just clearing the vector won't do it because the vector is storing the pointers and not the actual objects(it won't destroy but what it contains).
// if you just do
G.clear() // will clear the vector but you'll be left with 2 memory leaks
...
// to properly clean the vector and the objects behind it
for (std::vector<gate*>::iterator it = G.begin(); it != G.end(); it++)
{
delete (*it);
}
boost::ptr_vector<> will handle the above for you - meaning it will deallocate the memory behind the pointers it stores.
Through Boost you can do it
>
std::vector<boost::any> vecobj;
boost::shared_ptr<string> sharedString1(new string("abcdxyz!"));
boost::shared_ptr<int> sharedint1(new int(10));
vecobj.push_back(sharedString1);
vecobj.push_back(sharedint1);
>
for inserting different object type in your vector container. while for accessing you have to use any_cast, which works like dynamic_cast, hopes it will work for your need.
#include <memory>
#include <iostream>
class SharedMemory {
public:
SharedMemory(int* x):_capture(x){}
int* get() { return (_capture.get()); }
protected:
std::shared_ptr<int> _capture;
};
int main(int , char**){
SharedMemory *_obj1= new SharedMemory(new int(10));
SharedMemory *_obj2 = new SharedMemory(*_obj1);
std::cout << " _obj1: " << *_obj1->get() << " _obj2: " << *_obj2->get()
<< std::endl;
delete _obj2;
std::cout << " _obj1: " << *_obj1->get() << std::endl;
delete _obj1;
std::cout << " done " << std::endl;
}
This is an example of shared_ptr in action. _obj2 was deleted but pointer is still valid.
output is,
./test
_obj1: 10 _obj2: 10
_obj2: 10
done
The best way to add different objects into same container is to use make_shared, vector, and range based loop and you will have a nice, clean and "readable" code!
typedef std::shared_ptr<gate> Ptr
vector<Ptr> myConatiner;
auto andGate = std::make_shared<ANDgate>();
myConatiner.push_back(andGate );
auto orGate= std::make_shared<ORgate>();
myConatiner.push_back(orGate);
for (auto& element : myConatiner)
element->run();