I have some data class which is expensive to copy, but must be mutable, as it is frequently updated according to events. I also need a multi-index container to hold many such classes. I'm trying to set it up using boost::multi_index. For example:
struct MutableAndExpensiveToCopy {
int some_value;
std::map<int, std::string> some_huge_map;
std::map<int, std::string> an_even_bigger_map;
}
struct CanBeMultiIndexed
{
// "Payload" - its fields will never be used as indices
MutableAndExpensiveToCopy data;
// Indexes
int id;
std::string label;
}
typedef multi_index_container<
CanBeMultiIndexed,
indexed_by<
ordered_unique<member<CanBeMultiIndexed, int, &CanBeMultiIndexed::id>>,
ordered_non_unique<member<CanBeMultiIndexed,std::string,&CanBeMultiIndexed::label>>
>
> MyDataContainer;
My problem is that multi_index treats elements in the container as constants (in order to keep the integrity of all of the indices). For example, the following won't compile:
void main() {
// put some data in the container
MyDataContainer container;
CanBeMultiIndexed e1(1, "one"); // conto'r not shown in class definition for brevity
CanBeMultiIndexed e2(2, "two");
container.insert(e1);
container.insert(e2);
// try to modify data
MyDataContainer::nth_index<1>::type::iterator iter = container.get<1>().find(1);
iter->data.some_value = 5; // constness violation
}
I cannot use the replace() method, as it is expensive to copy the payload class.
I'm aware of the modify() method, but using it seems cumbersome, since in my real program, the "payload" class may contain numerous fields, and writing a functor for each and every one it out of the question.
Any suggestions?
EDIT: After some playing around, I've tried replacing the data element with a shared_ptr to MutableAndExpensiveToCopy:
struct CanBeMultiIndexed
{
// "Payload" - its fields will never be used as indices
boost::shared_ptr<MutableAndExpensiveToCopy> data;
// Indexes
int id;
std::string label;
}
This worked, and I was able to compile my main() including the data-modifying code:
void main() {
...
iter->data->some_value = 5; // this works
...
}
This pretty much gives me what I wanted, but I'm not sure why this works, so:
Does this code does what I intended, or is there some caveat I'm missing?
How come this works? Does the constness of the shared_ptr does not apply to its -> operator?
First of all, ImMutableAndExpensiveToCopy seems precisely to be the opposite --mutable, since you're trying to change its contents in the example. Try simply this:
struct CanBeMultiIndexed
{
mutable ImMutableAndExpensiveToCopy data;
int id;
std::string label;
}
(and possibly change the name ImMutableAndExpensiveToCopy for consistency.)
Related
Suppose I have a Container.
template<typename Type>
class Container
{
public:
Container(int size_)
{
size=size_;
data = new Type[size];
}
~Container()
{
delete [] data;
}
private:
int size;
Type* data;
};
I want construct the container and fill data into it in one line like this using C++03
// very easy to implement using C++11 std::initializer_list
Container<int> container{100,200,300}
or
Container<int> container(100,200,300)
or
// other one line solution
after do this, data[0]=100,data[1]=200,data[2]=300.
Thanks for your time.
Appendix
Similiar question is
How to fill data into container at once without temp variable in C++03
Evg already give the answer can implement a two lines solution.
Container<int> container(3);
container << 100, 200, 300;
I still wonder is there exist the one line solution?
The answer you link can almost do that. You only need a minor modification and that is: You need to make your container resizable. This is actually the major issue. Once you have that, adapting the solution is minor. Write a insert method that reallocates the memory and adjusts the size then only minor modifications on the proposed solution are necessary.
There is one caveat, and this is you cannot call the constructur call methods on the constructed object and assign it to a variable in the same line without a copy. For that it is possible to provide a conversion from Proxy to Container. I would rethink if putting something on a single line is really worth this cost, when it can be done much easier on two lines.
I didn't include the implementation of insert, because that would be sort of a different question:
#include <iostream>
template<typename Type>
class Container {
private:
struct Proxy {
Container* container;
Proxy(Container* container) : container(container) {}
Proxy& operator,(Type value) {
container->insert(value);
return *this;
}
operator Container() { return *container; }
};
public:
// ...
void insert(const Type& value) {
std::cout << value;
}
Proxy operator<<(Type value) {
insert(value);
return Proxy(this);
}
};
int main() {
Container<int> container = (Container<int>() << 1,2,3);
}
Output:
123
PS:
The problem is that, there is Container x={1,2,3,....,1000} everywhere in my project using C++11. Now, I must omove to C++03, and there is no std::itializer_list
Yes that is a problem. I suppose 1,2,3,...1000 is just an oversimplified example, otherwise you could use something similar to std::iota to fill the container (also only avaible since C++11, but not too difficult to implement). If that is the actual problem and you are looking for a temporary hack I would rather use plain arrays and construct the container from that:
int temp[] = {1,2,3,4,5 ....};
Container<int> x( &temp[0], &temp[999]);
Guys I have a function like this (this is given and should not be modified).
void readData(int &ID, void*&data, bool &mybool) {
if(mybool)
{
std::string a = "bla";
std::string* ptrToString = &a;
data = ptrToString;
}
else
{
int b = 9;
int* ptrToint = &b;
data = ptrToint;
}
}
So I want to use this function in a loop and save the returned function parameters in a vector (for each iteration).
To do so, I wrote the following struct:
template<typename T>
struct dataStruct {
int id;
T** data; //I first has void** data, but would not be better to
// have the type? instead of converting myData back
// to void* ?
bool mybool;
};
my main.cpp then look like this:
int main()
{
void* myData = nullptr;
std::vector<dataStruct> vec; // this line also doesn't compile. it need the typename
bool bb = false;
for(int id = 1 ; id < 5; id++) {
if (id%2) { bb = true; }
readData(id, myData, bb); //after this line myData point to a string
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
}
}
Or is there a better way to do that without template? I used c++11 (I can't use c++14)
The function that you say cannot be modified, i.e. readData() is the one that should alert you!
It causes Undefined Behavior, since the pointers are set to local variables, which means that when the function terminates, then these pointers will be dangling pointers.
Let us leave aside the shenanigans of the readData function for now under the assumption that it was just for the sake of the example (and does not produce UB in your real use case).
You cannot directly store values with different (static) types in a std::vector. Notably, dataStruct<int> and dataStruct<std::string> are completely unrelated types, you cannot store them in the same vector as-is.
Your problem boils down to "I have data that is given to me in a type-unsafe manner and want to eventually get type-safe access to it". The solution to this is to create a data structure that your type-unsafe data is parsed into. For example, it seems that you inteded for your example data to have structure in the sense that there are pairs of int and std::string (note that your id%2 is not doing that because the else is missing and the bool is never set to false again, but I guess you wanted it to alternate).
So let's turn that bunch of void* into structured data:
std::pair<int, std::string> readPair(int pairIndex)
{
void* ptr;
std::pair<int, std::string> ret;
// Copying data here.
readData(2 * pairIndex + 1, ptr, false);
ret.first = *reinterpret_cast<int*>(ptr);
readData(2 * pairIndex + 2, ptr, true);
ret.second = *reinterpret_cast<std::string*>(ptr);
}
void main()
{
std::vector<std::pair<int, std::string>> parsedData;
parsedData.push_back(readPair(0));
parsedData.push_back(readPair(1));
}
Demo
(I removed the references from the readData() signature for brevity - you get the same effect by storing the temporary expressions in variables.)
Generally speaking: Whatever relation between id and the expected data type is should just be turned into the data structure - otherwise you can only reason about the type of your data entries when you know both the current ID and this relation, which is exactly something you should encapsulate in a data structure.
Your readData isn't a useful function. Any attempt at using what it produces gives undefined behavior.
Yes, it's possible to do roughly what you're asking for without a template. To do it meaningfully, you have a couple of choices. The "old school" way would be to store the data in a tagged union:
struct tagged_data {
enum { T_INT, T_STR } tag;
union {
int x;
char *y;
} data;
};
This lets you store either a string or an int, and you set the tag to tell you which one a particular tagged_data item contains. Then (crucially) when you store a string into it, you dynamically allocate the data it points at, so it will remain valid until you explicitly free the data.
Unfortunately, (at least if memory serves) C++11 doesn't support storing non-POD types in a union, so if you went this route, you'd have to use a char * as above, not an actual std::string.
One way to remove (most of) those limitations is to use an inheritance-based model:
class Data {
public:
virtual ~Data() { }
};
class StringData : public Data {
std::string content;
public:
StringData(std::string const &init) : content(init) {}
};
class IntData : public Data {
int content;
public:
IntData(std::string const &init) : content(init) {}
};
This is somewhat incomplete, but I think probably enough to give the general idea--you'd have an array (or vector) of pointers to the base class. To insert data, you'd create a StringData or IntData object (allocating it dynamically) and then store its address into the collection of Data *. When you need to get one back, you use dynamic_cast (among other things) to figure out which one it started as, and get back to that type safely. All somewhat ugly, but it does work.
Even with C++11, you can use a template-based solution. For example, Boost::variant, can do this job quite nicely. This will provide an overloaded constructor and value semantics, so you could do something like:
boost::variant<int, std::string> some_object("input string");
In other words, it's pretty what you'd get if you spent the time and effort necessary to finish the inheritance-based code outlined above--except that it's dramatically cleaner, since it gets rid of the requirement to store a pointer to the base class, use dynamic_cast to retrieve an object of the correct type, and so on. In short, it's the right solution to the problem (until/unless you can upgrade to a newer compiler, and use std::variant instead).
Apart from the problem in given code described in comments/replies.
I am trying to answer your question
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
Before that you need to modify vec definition as following
vector<dataStruct<void>> vec;
Now you can simple push element in vector
vec.push_back({id, &mydata, bb});
i have tried to modify your code so that it can work
#include<iostream>
#include<vector>
using namespace std;
template<typename T>
struct dataStruct
{
int id;
T** data;
bool mybool;
};
void readData(int &ID, void*& data, bool& mybool)
{
if (mybool)
{
data = new string("bla");
}
else
{
int b = 0;
data = &b;
}
}
int main ()
{
void* mydata = nullptr;
vector<dataStruct<void>> vec;
bool bb = false;
for (int id = 0; id < 5; id++)
{
if (id%2) bb = true;
readData(id, mydata, bb);
vec.push_back({id, &mydata, bb});
}
}
I'm looking for a C++ container to store pointers to objects which also meets the following requirements.
A container that keeps the order of elements (sequence container, so std::set is not suitable)
A container that has a member function which return the actual size (As std::array::size() always returns the fixed size, std::array is not suitable)
A container that supports random accesses such as operator [].
This is my code snippet and I'd like to remove the assertions used for checking size and uniqueness of elements.
#include <vector>
#include <set>
#include "assert.h"
class Foo {
public:
void DoSomething() {
}
};
int main() {
// a variable used to check whether a container is properly assigned
const uint8_t size_ = 2;
Foo foo1;
Foo foo2;
// Needs a kind of sequential containers to keep the order
// used std::vector instead of std::array to use member function size()
const std::vector<Foo*> vec = {
&foo1,
&foo2
};
std::set<Foo*> set_(vec.begin(), vec.end());
assert(vec.size() == size_); // size checking against pre-defined value
assert(vec.size() == set_.size()); // check for elements uniqueness
// Needs to access elements using [] operator
for (auto i = 0; i < size_; i++) {
vec[i]->DoSomething();
}
return 0;
}
Is there a C++ container which doesn't need two assertions used in my code snippet? Or should I need to make my own class which encapsulates one of STL containers?
So a class that acts like a vector except if you insert, it rejects duplicates like a set or a map.
One option might be the Boost.Bimap with indices of T* and sequence_index.
Your vector-like indexing would be via the sequence_index. You might even be willing to live with holes in the sequence after an element is erased.
Sticking with STLyou could implement a bidirectional map using 2 maps, or the following uses a map and a vector:
Note that by inheriting from vector I get all the vector methods for free, but I also risk the user downcasting to the vector.
One way round that without remodelling with a wrapper (a la queue vs list) is to make it protected inheritance and then explicitly using all the methods back to public. This is actually safer as it ensures you haven't inadvertently left some vector modification method live that would take the two containers out of step.
Note also that you would need to roll your own initializer_list constructor if you wanted one to filter out any duplicates. And you would have to do a bit of work to get this thread-safe.
template <class T>
class uniqvec : public std::vector<T*>
{
private:
typedef typename std::vector<T*> Base;
enum {push_back, pop_back, emplace_back, emplace}; //add anything else you don't like from vector
std::map <T*, size_t> uniquifier;
public:
std::pair<typename Base::iterator, bool> insert(T* t)
{
auto rv1 = uniquifier.insert(std::make_pair(t, Base::size()));
if (rv1.second)
{
Base::push_back(t);
}
return std::make_pair(Base::begin()+rv1.first.second, rv1.second);
}
void erase(T* t)
{
auto found = uniquifier.find(t);
if (found != uniquifier.end())
{
auto index = found->second;
uniquifier.erase(found);
Base::erase(Base::begin()+index);
for (auto& u : uniquifier)
if (u.second > index)
u.second--;
}
}
// Note that c++11 returns the next safe iterator,
// but I don't know if that should be in vector order or set order.
void erase(typename Base::iterator i)
{
return erase(*i);
}
};
As others have mentioned, your particular questions seems like the XY problem (you are down in the weeds about a particular solution instead of focusing on the original problem). There was an extremely useful flowchart provided here a number of years ago (credit to #MikaelPersson) that will help you choose a particular STL container to best fit your needs. You can find the original question here In which scenario do I use a particular STL container?.
My apologies in advance, but I can't find this one.
In C++ I want a have a map. This map will consist of <string, Object>; where the objects are added dynamical from an XML document during runtime. The Object will either be a int, double, string, or array of ints, doubles, or string. The key is guaranteed to be unique. However, I need a way to dynamically declare this using a map.
Is this perhaps an instance when I should be using a template for the data part?
I can't use a large lib such as boost to achieve this, since this should be a light wight program.
(Ref: Use boost C++ libraries?)
This is similar to what im trying to achieve. Where the user specified the primitive type: (Ref: Creating dictionary that map type T as key to instance of type T)
std::map <std::string, ????> Values;
Edit:
So if I can't use boost, could I achieve this using a template?
In boost I am dong this:
typedef boost::variant<int, double, std::string> datum;
std::map<std::string, datum> Parms;
Then I later adding values during run-time (from XML, where each element has an attribute with the specified type)
Parms["a"] = 10; // int
Parms["b"] = 102.2039; // double
Parms["c"] = 6.6667e-07; // another double
Parms["d"] = "Hello world"; // std::string
The problem is when I do this:
datum v1 = obj.get("c"); // need double, not datum
You could consider embedding your primitive type in a struct. You can define a base class from which the different structs are derived. You probably need to save the type as well into the struct, but I left it out for simplicity.
If you really need the primitive types, ignore my answer and go for Boost.
#include <map>
#include <string>
struct BaseObject {};
struct ObjectInt : public BaseObject
{
int a;
};
struct ObjectString : public BaseObject
{
std::string a;
};
int main()
{
BaseObject *oi, *os;
oi = new ObjectInt;
os = new ObjectString;
std::map<std::string, BaseObject *> objectMap;
objectMap["oi"] = oi;
objectMap["os"] = os;
delete oi;
delete os;
return 0;
}
Here's a relatively small but segfaulting project. I've searched quite a few posts doing similar things and while many seemed to be having the same problem, none solved my problem.
The basic issue is this: I have an object (myGraph) with a member vector, and a few methods. A method inside another class invokes one of myGraph's methods, which in turn invokes another one. Inside that function, a push is made to a vector of ints in myGraph. However, this push results in a segfault.
In a somewhat extreme measure, I've been commenting out large portions of code (on a fresh branch of course) and have reduced my code down to a sparse few items. (other posts seemed to indicate that this kind of thing might be caused by bad code elsewhere) yet I am still getting a segfault.
What follow are the watered-down files, composed of the few things remaining uncommented. I say "watered-down" because a lot of declarations (of now-empty functions and such) have been removed. If you need additional information (for instance, if it's important - somehow - that I'm using a virtual function somewhere... as a radical example) just let me know.
in Dispatcher.h:
class myGraph;
class CDispatcher
{
public:
CDispatcher(void);
~CDispatcher(void);
void ProcessCall(string buf);
myGraph* mymap;
};
in Dispatcher.cpp:
void CDispatcher::ProcessCall(string buf)
{
mymap->getDistance(0,1);
};
in mygraph.cpp:
int myGraph::getDistance(int start, int end) {
Dijkstras(start,end);
// This is just to return something
return 5;
};
vector<int> myGraph::Dijkstras(int startVert,int endVert) {
vertices_i.push_back(2); // This line results in a segfault
cout << "push successful" << endl;
// This is just to return something
vector<int> unvisited;
return unvisited;
};
mygraph.h:
typedef struct edge
{
int endVert;
int weight;
} edge;
typedef struct vertex
{
long dist;
bool visited;
int prev;
vector<edge> edges;
} vertex;
class myGraph
{
public:
myGraph(int initSize);
~myGraph(void);
int getDistance(int start, int end);
vector<int> Dijkstras(int startVert,int endVert);
//vector<vertex> vertices; // The original vector that was segfaulting
vector<int> vertices_i; // Simpler vector, of just ints. Still segfaults
};
The unavoidable conclusion is that the member pointer myGraph* mymap is pointing to garbage; you've apparently neglected to initialize it to point to a myGraph object. You need to create an object for it to refer to in the CDispatcher constructor -- i.e.,
CDispatcher(void) : mymap(new myGraph(1)) {}