I'm trying to allocate a list for each key of my std map, but using the new operator I obtain some errors (no predefined constructor is find and others), why?
My code is like this one:
std::map<QString, *std::list<ExecutionGUIObject*>> execEvtMap;
execEvtMap["t1"] = new std::list<ExecutionGUIObject*>;
*std::list<ExecutionGUIObject*>
is not a valid type and hence not a valid argument to the std::map template. You probably meant
std::list<ExecutionGUIObject*>*
which means 'pointer to list of pointers to ExecutionGUIObject objects'.
As stated by Frerich Raabe, it's a minor syntax error in your map declaration. But you gain nothing by allocating the std::list's dynamically, so why seek trouble ? Just use a map of lists.
std::map<QString, std::list<ExecutionGUIObject*>> execEvtMap;
// Creates a new (empty) list for key "t1" if one does not already exist.
void(execEvtMap["t1"]);
// Creates a new list for key "t1", or clears the existing one.
execEvtMap["t1"].clear();
// Erases a key and its list
execEvtMap.erase("t1");
If this maps owns the ExecutionGUIObject's, you'll want to tweak that too :
std::map<QString, std::list<std::unique_ptr<ExecutionGUIObject>>> execEvtMap;
Related
In C++ the indexing operator is defined for std::map and std::unordered_map so that if your reference to the container is non-const just the act of indexing without assigning is enough to have implicitly created a value inside the container. This sometimes creates subtle bugs, where you expect to be referencing a value inside a container but instead actually create one, e.g. config["stting"] instead of config["setting"].
I know Python addresses this by having __setitem__ and __getitem__ be separate methods but this requires cooperation with the parser.
Does Rust do anything to address this frequent source of bugs?
No Rust doesn't have that problem. There's no implicit creation of items in Rust collections.
For example you'd insert a key-value pair to a std::collections::HashMap with map.insert(key, value) and retrieve a value with let value = map.get(key);.
Note that .get() will return an Option<&V>, so if the key didn't exist you will get None as a result.
Rust also offers an easy way to either retrieve a value or to insert some default value for the given key if the value doesn't exist with:
let value = map.entry(key).or_insert(0);
HashMap also implements the Index trait, which allows retrieval of a value with let value = map[key];, which will panic if key doesn't exist in map.
Note that because HashMap does not implement IndexMut, this [ ] bracket syntax always returns an immutable reference to the value, so you cannot insert or modify values this way.
I am implementing a hashtable and am having trouble with the implementation. After literal hours of googling on this one thing, i've given up and was hoping to see of i could get any help here. The biggest issue is to do with the use of vectors in the HashTable(doesnt make sense to me, rather just use list<> but using it is required)
My main issue is to do with how to implement the insert function to add to the HashTable.
void HashTable::insert(ulint key,ulint value){ //insert data associated with key
HashNode nodeToAdd;
nodeToAdd.assign(key, value);
int index = hash_function(key);
this->table[index].push_back(nodeToAdd);
}
Now the issue im having is adding the HashNode to my HashTable.
for reference in HashTable, the field for the table is
typedef vector <list<HashNode> > Table;
Table *table;
So by my understanding
this->table[index].push_back(nodeToAdd);
is going to the vector HashTable[index], which at the index should be a list. and when it gets to that list, it should push_back the new node into the list.
However when compiled, i'm hit by an error(no matching function to call) and i don't understand why.
Your list stores objects of type HashNode, not type HashNode*.
So you need to decide which of those you want to use, and change the code accordingly.
If you want to keep storing HashNode, then your insert is wrong -- it should instead create the node on the stack and store it by value in the list.
If you want to store a pointer, then your Table type is wrong, and should instead be vector<list<HashNode*>> -- note it should be managed carefully since the pointers will not be automatically deleted.
Personally, I'd suggest you go with #1 and save yourself a whole lot of headaches. But if you insist on #2, then I suggest you stop using malloc and use new -- or better yet use std::unique_ptr or std::shared_ptr for automatic lifetime management.
Also noteworthy is your definition Table *table. This is baffling, since Table is a vector. Your insert function is dereferencing this pointer, expecting it to perhaps point to an array of Table values, when it's quite clear you actually think it's a vector. I'm pretty sure you don't want that to be a pointer.
Since I only just noticed that detail, I imagine that's the first source of your error, since table[index] is actually type Table, not type list<HashNode> and you were trying to call the non-existent function vector<list<HashNode>>::push_back(HashNode*).
So I'm pretty new to c++:
I have a class XMLItem.
I create an instance of the class XMLItem by
XMLItem the_item = XMLItem(params...);
I create a vector to hold XMLItems by
vector<XMLItem> my_vect;
However when I try to insert the_item into my_vect with
my_vect.insert(the_item);
I get the following output error:
error: no matching function for call ‘std::vector<XMLItem>::insert(XMLItem&)’
It looks like the compiler is complaining that I'm trying to insert a reference to an object of type XMLItem but I have no idea why that would be the case. Is there something I'm misunderstanding about initializing objects in c++?
insert operation requires a position. If position doesn't matter to your case then you can use emplace_back (C++11) or push_back.
std::vector::insert() inserts elements at the specified location in the container. You need to specify position. There is no any overload of insert() which takes one argument that's why compiler gives you an error. You should use push_back() or emplace_back() if you don't want to specify position.
This question already has answers here:
How can I create objects while adding them into a vector?
(5 answers)
Closed 9 years ago.
This is a pretty straight forward question.
Is there a way to have a vector and initialize an element without constructing and then copying it?
class BigType
{
// has a costly copy constructor
};
int main(void)
{
using std::vector;
vector<BigType> bigTypeVec;
bigTypeVec.push_back(BigType(/*constructor from parameters*/));
// This constructs a temp object, and then copies it to the new element.
}
Of course there are all sorts of work-a-rounds involving vectors of pointers, or instead of using a constructor, initialize an element's components with set functions, however I was wondering if there were a way to do it so that it can call the constructor on the element it allocates during push_back.
Edit: This question was marked as a duplicate, however I had viewed that page and the answers to his question hadn't answered mine. I want to know how to set the value of the element by constructing it once, rather then copy constructing a temporary object into the element. Emplace was a good way to do this.
You could use std::vector<...>::emplace() or, if you want to append the object, std::vector<...>::emplace_back(), to construct the object in place. If you have to use C++03 this member function isn't available. As an approximation you could push_back() and empty object and then swap() your BigType into the corresponding location, assuming you could construct a small empty object.
Note that std::vector<...> isn't necessarily the best data structure if you have huge objects: if the reserved spaces runs out, the vector need to shuffle the objects around to make new space. You might want to use std::deque<...> instead, as it won't leave its objects put (unless you insert into the middle) while having similar access characteristics as std::vector<...>.
with C++11, yes.
bigTypeVec.emplace_back(BigType());
Here's some more info:
http://en.cppreference.com/w/cpp/container/vector/emplace_back
"Is there a way to have a vector and initialize an element without constructing and then copying it?"
Yes.
Consider placement new as a mechanism to side-step the use of a copy assignment and it's use of a temporary.
"Is there a way to have a vector..."
A vector can be built with elements created with the default constructor.
I believe it is possible to define BigType so that no element initialization is required during the bigTypeVec construction. In this way, declaring the vector (or even a simple array) will trigger no element constructor work. Consider these:
vector<BigType> bigTypeVec;
or
BigType bigTypeVec[MAX_BigTypeVecSize];
Note that the array requires BigType to provide a default constructor (or you to provide a big bunch of curly brace array initialzation).
However, I can imagine that you might find value for each BigType element to have an indication that it is or is not initialized.
" and initialize an element without constructing [a temp] and then copying it [, the temp, to the vector]?"
Placement new can then be used to construct the object in place. By passing the address of the desired bigTypeVec element you wish to initialize to the placement new, all the element constructor work will occur where (in memory) you want it. Consider something like:
vector<BigType> bigTypeVec;
BigType* pBT = 0;
pBT = new (&bigTypeVec[0] BigType(<param>); // placement new
pBT = new (&bigTypeVec[1] BigType(<param>);
...
pBT = new (&bigTypeVec[n] BigType(<param>);
Note the discard of pBT. Pointer is not used.
*"I was wondering if there were a way to do it so that it can call the constructor on the element it allocates during push_back."*
At this point, all that remains is to create the simplest class possible that inherits from std::vector() and re-impliments "push back", or perhaps a new method that supports your needs. These methods would seek the vector element that push-back would have found, and use the placement new similar to above.
Are you sure about this?
"This constructs a temp object, and then copies it to the new element."
As far as I know, it will directly create an object at the memory location. Return value optimization. Temporary will not be created.
Am I wrong?
This one is gonna sting a little bit :\ . This is my map declaration:
std::map<std::string, std::shared_ptr<std::vector<std::shared_ptr<BaseEntity> > > > m_EntityByClassList;
really, the only reason it's so long is because of the smart pointer declarations, it's pretty much just this:
std::map<std::string, std::vector<BaseEntity *> *> m_EntityByClassList;
still painful to read though. here's my problem. When i try to insert an object into a new vector in the map, i get an "access violation trying to read" runtime error.
the chunk of code that yields this error is this,
for(;;)
{
file >> classname;
if(file.eof())
break;
m_EntityList.push_back( m_factory.createInstance(classname));
m_EntityList.back()->Initialize();
m_EntityList.back()->GetParams(file);
m_EntityByNameList[m_EntityList.back()->GetName()] = m_EntityList.back();
m_EntityByClassList[classname]->push_back(m_EntityList.back());
}
now yes, there is certaintly alot of code i am omitting here, mainly because theres a good 35 or 36 objects and files that go into this blurb here so i'm just going to list off the things relevant. file is an std::ifstream to an open file, classname is an std::string, m_EntityList is a std::vector<std::shared_ptr<BaseEntity> > (shouldn't matter), m_EntityByNameList is a map with indices type std::string and objects type std::shared_ptr<BaseEntity> (also shouldn't matter) and then the map above. all the statements above the last one work exactly correct with verfied results. If the last line is omitted, it compiles and works just dandy.
So this question has nothing to do with the rest of the files, and is only about trying to add a vector to a map and add objects to it. If you feel you need anything else, ask and i'll see about getting it posted up here. Posting everything would easily be 4000-4500 lines.
Annnnyway, what i've learned about maps from this is that using the [ ] operator with an indice that has yet to exist will have one created for you along with a default constructed object at that index. So what i get from this is that an std::shared_ptr<std::vector<std::shared_ptr<BaseEntity> > > will be created at the index classname which means i should be able to access the vector whether it had been created beforehand or just before. So does anyone have any clue what's up?
Using operator[] on the map with a nonexistent key will indeed insert a new shared_ptr. However, what you aren't taking into account is that the new shared_ptr will be empty (i.e. a null pointer), and therefore dereferencing it will cause undefined behavior. A new vector will not be created - since you are using pointers to vectors, you'll need to allocate a new vector yourself.
If your map's value type was the vector itself rather than a pointer to it, it would be created automatically as you expect.