For my GUI i need a class with the following purposes to manage controls (windows, buttons etc)
[index]
["key"]
ptr=&container[index]
wont change if elements are added or erasedcontainer2=conatiner1
(deep-copy)ptr1=container[1]
and ptr2=container[2]
, then after swapping the order of 1 and 2, ptr1==container[2]
and ptr2==container[1]
I came to the conclusion that std::list provides the stability for the pointers that I need and std::vector the random access. So I have the idea to store a tuple of std string and iterator in a vector. However, the iterators are all invalid after the container is copied.
Any suggestions on how to tackle this problem best?
Here the main code of the current approach (only important parts are included):
template < class T >
class ControlList
{
struct Tuple{std::string first;typename std::list<T>::iterator second;};
std::vector<Tuple> list;
std::list<T> objects;
inline T& operator [](int i)
{
return *list[i].second;
}
inline T& operator [](std::string s)
{
loopi(0,vlist.size())
if(s==vlist[i].first)
return *vlist[i].second;
}
}
The string access is slow, but usually the container has not more than 10 elements and its used rarely in the program.
Update:
The shared pointer is already good, but cannot solve for the deep copy I need. Lets say I have window2=window1. Now if I have a shared pointer, then pushing a button in window2 also pushes the same button in window1, which is not wanted. I really need a new instance of all objects contained in the container.
Is it possible to override the copy constructor to create new instances of the objects referenced by the smart pointers ?
Both, windows and buttons are stored in a ControlList
, where a window contains multiple lists.
Update2:
Overriding the copy constructor and the assignment constructor has apparently solved the problem
Update3:
I just released the GUI this class was intended for under MIT.
Download here.
If you were to use std::vector<std::pair<std::string, std::unique_ptr<T>>>
, you could copy the items however you wanted to, and the resulting value would just require one more step of indirection to access. This would eliminate much of the complexity you have right now with 3 different structures. As a bonus, the items would also automatically cleanup after itself.
If you require owner-observer semantics with the pointers, you could instead opt for std::shared_ptr<T>
and std::weak_ptr<T>
. Shared pointers can easily create weak pointers, which act as non-owning observers which do not affect the referencing counting of the shared pointer.
Edit: Just to add on, shared_ptr
and the other smart pointers are C++11 and later-exlcusive. If you desire C++03-compatible solutions, you can look to past Boost implementations or perhaps create one yourself by observing the C++11/14 spec.
Edit2: Here is some code to assist:
http://coliru.stacked-crooked.com/a/a9bf52e5428a48af
#include <vector> //vector
#include <memory> //smart pointers
#include <utility> //pair
#include <string> //string
#include <iostream>//cout
template <class T>
class Container {
public:
inline void push(const std::string& s, const T& t) {
objects.push_back(std::pair<std::string, std::shared_ptr<T>>(s, std::make_shared<T>(t)));
}
inline T& operator [](const size_t& i)
{
return *(objects[i]->second);
}
inline T& operator [](const std::string& s)
{
for (auto it : objects) {
if(s == it.first) {
return *(it.second);
}
}
//welp, what do you do here if you can't find it?
}
private:
std::vector<std::pair<std::string, std::shared_ptr<T>>> objects;
};
int main() {
Container<int> cont;
std::string str {"hi"};
int i {2};
cont.push(str, i);
//This is good...
std::cout << cont["hi"] << std::endl;
//But undefined behavior!
std::cout << cont["02"] << std::endl;
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With