I am getting the following error while compiling my C++ program:
error: no matching function for call to 'std::vector<ChainingTable<int>::Record, std::allocator<ChainingTable<int>::Record> >::push_back(ChainingTable<int>::Record*)'
324 | vector_.push_back(new Record(key, value));
The error is coming from the line:
template <class TYPE>
bool ChainingTable<TYPE>::update(const std::string &key, const TYPE &value)
{
if (!keyExists)
{
vector_.push_back(new Record(key, value));
}
}
This is defined for the class:
class ChainingTable : public Table<TYPE>
{
struct Record
{
TYPE data_;
std::string key_;
Record(const std::string &key, const TYPE &data)
{
key_ = key;
data_ = data;
}
};
std::vector<std::vector<Record>> records_;
int capacity_; // capacity of the array
Complete code:
int sz = numRecords();
bool rc = true;
std::hash<std::string> hashFunction;
size_t hash = hashFunction(key);
size_t idx = hash % capacity_;
std::vector<Record> vector_ = records_[idx];
bool keyExists = false;
for (int i = 0; i < vector_.size(); i++)
{
if (vector_[i].key_ == key)
{
vector_[i].data_ = value;
keyExists = true;
}
}
if (!keyExists)
{
vector_.push_back(new Record(key, value));
}
What could be the reason for this?
Your vector is declared to store objects of type Record, not pointers to them (Record *) but you are trying to push result of operator new which returns Record *, just use std::vector::emplace_back instead:
vector_.emplace_back(key, value);
Note: in this line
std::vector<Record> vector_ = records_[idx];
you create a copy and later modify it, seems that you need a reference.
Note2: in your search loop you do not terminate even if you find object already, you should add break into if statement, that will make it more effective.
The problem is that your variable vector_ holds objects of type Record but when you write:
vector_.push_back(new Record(key, value));
You are trying to add a pointer to a Record object in the vector vector_ instead of adding the Record object itself.
You can solve it by writing:
vector_.emplace_back(key, value);
Alternate solution
Note that there is another possible solution which is to use:
vector_.push_back(Record(key, value));
But using emplace_back should be preferred.
Related
This is giving me an operator error when I compile it. No other error show up.
#include <map>
struct RESOURCE {
char Name[MAX_PATH] = { NULL };
int Level = 0;
};
struct RESOURCEFILE {
char FileName[MAX_PATH] = { NULL };
DWORD ATTRIBUTE = 0;
};
map <RESOURCE, RESOURCEFILE> ResourcesMap;
void PolulateResources(RESOURCE Resource, RESOURCEFILE File){
ResourcesMap[Resource] = File;
};
The reason this doesn't compile is because you are trying to use a map with key type RESOURCE. By default the compare function for std::map uses less-than-operator(<) for the key type to order the map. You haven't defined one here.
You can fix the issue by defining a operator< for RESOURCE:
struct RESOURCE {
char Name[MAX_PATH] = { NULL };
int Level = 0;
bool operator<(const RESOURCE& other) const
{
//write your compare function here...
//return (strcmp(Name, other.Name) < 0);
}
};
(It might be easier to use std::string for Name since it already has a operator<).
Alternatively you could define a functor or a lambda for the compare function.
I'm just trying to get C++ down and to do that, I gotta make my own libraries and whatnot. So I'm trying to get the beginnings of my own List template class, exactly like the List class in the JDK. So I've got the template and stuff down, I just wanna know how I would make it so that I could loop through the contents of a list object. This way I can print out the contents of said object. I don't exactly know where to start.
#pragma once
template<typename T> class List {
public:
List() : _size(0), _elements(nullptr) {}
~List() {
if (_elements != nullptr) {
delete[] _elements;
}
}
inline int size() { return _size; }
inline void add(T element) {
_size++;
T* buffer = new T[_size];
if (_elements != nullptr) {
memcpy(buffer, _elements, sizeof(T) * (_size - 1));
delete[] _elements;
}
buffer[_size - 1] = element;
_elements = buffer;
}
inline void remove(T element) {
_size--;
T* buffer = new T[_size];
if (_elements != nullptr) {
memcpy(buffer, _elements, sizeof(T) * _size);
delete[] _elements;
}
else {
assert(false);
}
_elements = buffer;
}
inline T* getElements() {
return _elements;
}
private:
int _size;
T* _elements;
};
And this is my main Cpp file
#include <cstdio>
#include <string>
#include "List.h"
using namespace std;
int main( int argc, char ** argv )
{
string str = "This is a test!";
List<char> list = breakString(str);
for (char c : list.getElements()) {
}
getchar();
return 0;
}
List<char> breakString(string str) {
List<char> list;
for (char c : str) {
list.add(c);
}
return list;
}
So what I'm trying to figure out is in that for loop, I'm used to it being an enhanced for loop like in Java, and is that the same here in C++? If so, how would I make this object iterable?
I figured I would get a more accurate answer to my question if I asked directly.
The guidelines for validating the Range-based for can be found on http://en.cppreference.com/w/cpp/language/range-for
If range_expression is an expression of a class type C that has a member named begin and/or a member named end (regardless of the type or accessibility of such member), then begin_expr is __range.begin() and end_expr is __range.end();
In short, since your data is in a raw array, you should add these public methods to you class List<T>
T* begin() { return _elements;}
T* end() { return _elements + _size;}
And then you can invoke the Range-based for on the object directly:
for (char c : list)
But you have other issues in your code. One of them (not sure it's the only one) is that breakString returns an object, but your class is not trivial and it does not define any copy or move constructors.
This answer adresses the "main" question as to how the enable the Range-based for for your class. It just needs two methods begin() and end() that return something that looks like an iterator (could be an actual iterator or a pointer to a contiguous memory chunk")
You can test the suggested modifications without using breakString, like this:
int main( int argc, char ** argv )
{
std::string str = "This is a test!";
List<char> list;
for (char c : "abcdef") { list.add(c); }
for (char c : list) { std::cout << c << "\n"; }
}
And to make it "fully iterable" define you can define a nested class called ierator..
So i have created a class that creates an array of objects from another class and when i try to execute the program and insert new objects to the array i get this error: EXC_BAD_ACCESS(code=EXC_I386_GPFLT)
Specifically on the insertion of the 10th element.
this is the class that has the array:
class Savelist{
private:
list_reserve *reserve;
list_user *users;
int length,MaxSize;
string code;
public:
string stoixeia;
Savelist(int MaxListSize)
{// Constructor for formula-based linear list.
MaxSize = MaxListSize;
reserve = new list_reserve (MaxSize, code);
users=new list_user(MaxSize);
length = 0;
}
~Savelist() {delete [] reserve,delete [] users;} // destructor
bool IsEmpty() const {return length == 0;}
int Length() const {return length;}
the method that inserts class objects to array:
void Insert_flight(list_reserve input)
{// "push" all objects one position up
if (length!=0)
{
for (int i=length-1; i >=0; i--)
{
reserve[i]=reserve[i+1];
}
reserve[0] = input;
length++;
}
else
{
reserve[0] = input;
length++;
}
}
here is the class that creates the objects that are being inserted to array:
class list_reserve {
private:
bool result;
int length,MaxSize;
string *object; // dynamic 1D array
public:
string code;
bool get_result;
// constructor
list_reserve(int MaxListSize,string flcode)
{// Constructor for formula-based linear list.
MaxSize = MaxListSize;
object = new string [MaxSize];
length = 0;
code=flcode;
}
~list_reserve() {delete [] object;} // destructor
bool IsEmpty() const {return length == 0;}
int Length() const {return length;}
the method that inserts simple strings to the object of that class:
void Insert_User(string input,string code,list_flight schedule)
{// Insert user
if (length!=0)
{
for (int i=length-1; i >=0; i--)
{
object[i+1] = object[i];
}
object[0] = input;
schedule.Get(code);
schedule.update(schedule.code, 1);
length++;
}
else
{
object[0] = input;
schedule.Get(code);
schedule.update(schedule.code, 1);
length++;
}
}
};
And lastly the main():
int main(int argc, const char * argv[]) {
list_reserve DA001_r(100,"DA001"),DA002_r(100,"DA002"),DA003_r(100,"DA003"),DA004_r(100,"DA004"),DA005_r(100,"DA005")
,DA006_r(100,"DA006"),DA007_r(100,"DA007"),DA008_r(100,"DA008"),DA009_r(100,"DA009"),DA010_r(100,"DA010"),DA011_r(100,"DA011")
,DA012_r(400,"DA012"),DA013_r(400,"DA013"),DA014_r(100,"DA014"),DA015_r(100,"DA015"),DA016_r(100,"DA016"),DA017_r(100,"DA017")
,DA018_r(100,"DA018"),DA019_r(100,"DA029"),DA020_r(100,"DA020"),DA021_r(100,"DA021"),DA022_r(100,"DA022"),DA023_r(400,"DA023"),
DA024_r(400,"DA024");
Savelist Queues(100);
Queues.Insert_flight(DA001_r);
Queues.Insert_flight(DA002_r);
Queues.Insert_flight(DA003_r);
Queues.Insert_flight(DA004_r);
Queues.Insert_flight(DA005_r);
Queues.Insert_flight(DA006_r);
Queues.Insert_flight(DA007_r);
Queues.Insert_flight(DA008_r);
Queues.Insert_flight(DA009_r);
Queues.Insert_flight(DA010_r);
Queues.Insert_flight(DA011_r);
Queues.Insert_flight(DA012_r);
Queues.Insert_flight(DA013_r);
Queues.Insert_flight(DA014_r);
Queues.Insert_flight(DA015_r);
Queues.Insert_flight(DA016_r);
Queues.Insert_flight(DA017_r);
Queues.Insert_flight(DA018_r);
Queues.Insert_flight(DA019_r);
Queues.Insert_flight(DA020_r);
Queues.Insert_flight(DA021_r);
Queues.Insert_flight(DA022_r);
Queues.Insert_flight(DA023_r);
Queues.Insert_flight(DA024_r);
}
You really, really don't want to store owning pointers to dynamically allocated resources in classes. For a good rundown on why see this answer on what's necessary to store an owning pointer in a class. Using a standard container such as std::vector also greatly simplifies the code as these implement most common operations you may want to do with them, such as insertion, deletion and the like.
For instance, your Savelist class would become the following when using std::vector
class Savelist {
private:
vector<list_reserve> reserve;
vector<list_user> users;
// No need for storing MaxSize or length, std::vector can store any
// number of elements, and knows how many elements it contains.
string code;
public:
string stoixeia;
// constructor and destructor becomes unnecessary, as the vector member
// takes care of all the bookkeeping
bool IsEmpty() const { return reserve.empty(); }
int Length() const { return reserve.size(); }
// Insert flight need only pass the input to the vector
void Insert_flight(list_reserve input) { reserve.insert(reserve.begin(), input); }
};
And similarly for the list_reserve class
class list_reserve {
private:
bool result;
// once again, the vector keeps track of size and elements contained
vector<string> object;
public:
string code;
bool get_result;
// constructor becomes simpler
list_reserve(string flcode)
{
code = flcode;
}
// destructor becomes unnecessary
bool IsEmpty() const { return object.empty(); }
int Length() const { return object.size(); }
void Insert_User(string input, string code, list_flight schedule)
{
// note that object.push_back(input); would be
// more efficient, but inserts the element at the end.
object.insert(object.begin(), input);
schedule.Get(code);
schedule.update(schedule.code, 1);
}
};
See also cppreference page on std::vector for an excellent reference on what's available.
I created a class Route which I wanted to store in an std::set. A Route is indexed by an Id, so what I want is to be able to have an expression like
class RouteTemplate
{
Route *RouteTemplate::getRoute(const char *pId);
Route::ptr_set mRoutes;
};
Route *RouteTemplate::getRoute(const char *pId)
{
Route::ptr_set::const_iterator pos = mRoutes.find(pId);
if(pos == mRoutes.end())
return NULL;
return *pos;
}
However I get a compiler error.
conversion from 'const char *' to 'Route *const ' not possible
As far as I know I have to implement the comparator, which I did.
class Route
{
public:
static const size_t _id_len = 11;
class comparator
{
public:
bool operator() (const Route &oLeft, const Route &oRight) const
{
return oLeft < oRight;
}
};
class ptr_comparator
{
public:
bool operator() (const Route *oLeft, const Route *oRight) const
{
return (*oLeft) < (*oRight);
}
};
typedef std::set<Route, Route::comparator> set;
typedef std::set<Route *, Route::ptr_comparator> ptr_set;
public:
Route(void);
Route(const char *oId);
virtual ~Route(void) {};
inline bool operator<(const Route &oOther) const
{
return strncmp(mId, oOther.mId, _id_len) < 0;
}
inline bool operator<(const char *oId) const
{
if(!oId)
return false;
return strncmp(mId, oId, _id_len) < 0;
}
inline const char *getId(void) const { return mId; }
inline void setId(const char *oId)
{
if(oId == NULL)
mId[0] = 0;
else
{
strncpy(mId, oId, sizeof(mId));
mId[_id_len] = 0;
}
}
private:
char mId[_id_len+1];
// Additional members
};
I assume you want to leverage the templated overload of std::set::find that was added in C++14. Before that, you could only find() a key of the Key type that is used for the std::set. So, the first thing to do is using a C++14 compiler.
Second, that additional overload can only function if the resulting comparison has the same semantics as would have constructing a (temporary) key and comparing it with the std::sets comparator. If I'm not missing anything, your comparators would qualify for this. However, to avoid accidental mistakes, you have to explicitly confirm that by giving the Compare type a type member is_transparent.
If you can live with a temporary being created, you could explicitly ask for it. This should work.
Route *RouteTemplate::getRoute(const char *pId)
{
Route temporary_key {pId};
Route::ptr_set::const_iterator pos = mRoutes.find(&temporary_key);
if(pos == mRoutes.end())
return NULL;
return *pos;
}
You could also overload operator&, to allow invoking it on temporary object. This would simplify usage o find method as you could create Route object on the fly and then apply operator& at this temporary.
class Route
{
public:
...
Route* operator&() { return this; }
...
}
Then it would be valid to write getRoute() method like:
Route *RouteTemplate::getRoute(const char *pId)
{
Route::ptr_set::const_iterator pos = mRoutes.find(&Route(pId));
if (pos == mRoutes.end())
return NULL;
return *pos;
}
I have class called "UltrasoundTemplate". These UltrasoundTemplate objects contain an int parameter, which shows when they where defined (something like a time stamp). And I have a class called "UltrasoundTarget" which contains a vector of UltrasoundTemplate's.
I add UltrasoundTemplates to the vector with push_back(ultrasoundTemplate).
Now I want to sort the vector by the order of time stamps instead of the order I added them to the vector.
I found a lot of answers in google, which all show me the same solution, but obviously I'm still doing something wrong. Here are the code snippets I think are necessary for finding a solution:
ultrasoundTemplate.h
class UltrasoundTemplate
{
public:
UltrasoundTemplate(/*...*/);
int getVolumePos() { return volume_; }
private:
int volume_;
};
ultrasoundTarget.h
//the sort algorithm
struct MyTemplateSort {
bool operator() ( UltrasoundTemplate t1, UltrasoundTemplate t2){
int it1 = t1.getVolumePos();
int it2 = t2.getVolumePos();
if (it1 < it2)
return true;
return false;
}
};
class UltrasoundTarget
{
public:
UltrasoundTarget(/*...*/);
vector<UltrasoundTemplate> getTemplates() { return USTemplateVector_; }
private:
vector<UltrasoundTemplate> USTemplateVector_;
};
FMainWindow.cpp
void FMainWindow::match_slot()
{
int i;
//here I get the name of the target I'm looking for
QTreeWidgetItem *item = targetInfoWidget_->treeWidget->currentItem();
int index = targetInfoWidget_->treeWidget->indexOfTopLevelItem(item);
QString itemToAppendName = item->text(0);
for(i = 0; i < USTargetVector.size(); i++){
if(USTargetVector.at(i).getName() == itemToAppendName) {
//here I try to sort
MyTemplateSort tmpltSrt;
std::sort(USTargetVector.at(i).getTemplates().begin(),
USTargetVector.at(i).getTemplates().end(), tmpltSrt);
break;
}
}
As an example: I define Template1 in Volume(0), Template2 in Volume(70) and Template3 in Volume(40). The order now is (Template1, Template2, Template3) but I want it to be (Template1, Template3, Template2). But this code is not doing it.
If there's Information missing, just tell me and I'll provide more code.
Thanks alot.
Your getTemplates() method returns by value, making a mess here:
std::sort(USTargetVector.at(i).getTemplates().begin(),
USTargetVector.at(i).getTemplates().end(), tmpltSrt);
You are sorting an incompatible iterator range. You can fix that particular problem by returning a reference:
vector<UltrasoundTemplate>& getTemplates() { return USTemplateVector_; }
It is common practice to add a const overload to such a method:
const vector<UltrasoundTemplate>& getTemplates() const { return USTemplateVector_; }
You can also modify your comparison functor to avoid unnecessary copies (and for general readability and const correctness):
struct MyTemplateSort {
bool operator() const ( const UltrasoundTemplate& t1, const UltrasoundTemplate& t2)
{
return t1.getVolumePos() < t2.getVolumePos();
}
};
This will require that you make getVolumePos() a const method, which it should be anyway:
class UltrasoundTemplate
{
public:
...
int getVolumePos() const { return volume_; }
...
};
Note that is is not generally good practice to provide references to the private data of a class. If possible, you should find a way to remove that from the UltraSoundTarget interface. You could, for instance, expose a pair of iterators, and/or give the class a sort method.
juanchopanza answer is correct, the problem is the way you are returning the vector from UltrasoundTarget. Just to touch another topic, maybe it would be nice to change a little the designing of your implementation. As UltrasoundTarget is a container of Ultrasound's, it makes sense to implement the sort as a method of this class, this way you have direct access to USTemplateVector_ and will save unecessary copies. Something like:
class UltrasoundTarget
{
public:
UltrasoundTarget(/*...*/);
vector<UltrasoundTemplate> getTemplates() { return USTemplateVector_; }
void sort();
private:
vector<UltrasoundTemplate> USTemplateVector_;
};
void UltrasoundTarget::sort()
{
std::sort(USTemplateVector_.begin(), USTemplateVector_.end(), tmpltSrt);
}
void FMainWindow::match_slot()
{
int i;
//here I get the name of the target I'm looking for
QTreeWidgetItem *item = targetInfoWidget_->treeWidget->currentItem();
int index = targetInfoWidget_->treeWidget->indexOfTopLevelItem(item);
QString itemToAppendName = item->text(0);
for(i = 0; i < USTargetVector.size(); i++){
if(USTargetVector.at(i).getName() == itemToAppendName)
{
//here I try to sort
MyTemplateSort tmpltSrt;
USTargetVector.at(i).sort();
break;
}
}