A question about the find function of Google dense_hash_map - c++

I use Google’s dense_hash_map as a cache of some data. When I use the find function to find a key, I find that it doesn’t exist, but when traversing dense_hash_map, I can see that the key exists. Is it wrong where I used it? By the way, I have rewritten the EqualKey class required by dense_hash_map.
This is my test code:
class StringVal {
public:
StringVal(string &str) {
len = str.length();
ptr = new uint8_t[len];
memcpy(ptr, str.c_str(), len);
}
StringVal(uint8_t* ptr = NULL, int len = 0) : len(len), ptr(ptr) {
if(ptr == NULL) {
is_null = NULL;
}
}
StringVal(const char* ptr) : len(strlen(ptr)),ptr(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(ptr))) {
if(ptr == NULL) {
is_null = NULL;
}
}
~StringVal() {
delete[] ptr;
}
uint8_t* ptr;
int len;
bool is_null;
static StringVal null() {
StringVal sv;
sv.is_null = true;
return sv;
}
bool operator==(const StringVal& other) const {
if (is_null != other.is_null) return false;
if (is_null) return true;
if (len != other.len) return false;
return ptr == other.ptr || memcmp(ptr, other.ptr, len) == 0;
}
bool operator!=(const StringVal& other) const { return !(*this == other); }
};
struct NewStringValCmp {
bool operator()(const StringVal* s1, const StringVal* s2) const {
if (s1 == NULL && s2 == NULL) return 1;
if (s1 == NULL || s2 == NULL) return 0;
if (s1->is_null != s2->is_null) return false;
if (s1->is_null) return true;
if (s1->len != s2->len) return false;
return memcmp(s1->ptr, s2->ptr, s1->len) == 0;
}
};
typedef dense_hash_map<StringVal*, StringVal*, std::hash<StringVal*>, NewStringValCmp> new_dict_map_string_t;
vector<string> data = {
"test1","1",
"test2","2",
"test3","3",
"test4","4",
"test5","5",
"test6","6",
"test7","7",
"test8","8",
"test9","9",
"test10","10"
};
int main() {
new_dict_map_string_t* cm = new new_dict_map_string_t();
cm->set_empty_key(NULL);
for (int i = 0; (i + 1) < data.size(); i+=2) {
StringVal *key = new StringVal(data[i]);
StringVal *value = new StringVal(data[i+1]);
(*cm)[key] = value;
}
string input = "";
while (1) {
cin >> input;
if (input == "q") {
break;
}
StringVal *target = new StringVal(input);
for (auto itor: *cm) {
if (*(itor.first) == *target) {
cout << "find target" << endl;
}
}
auto itor = cm->find(target);
if (itor == cm->end()) {
cout << "cm->find nothing" << endl;
} else {
cout << itor->second->ptr << endl;
}
delete target;
input = "";
}
for (auto iter : *cm) {
delete iter.first;
delete iter.second;
}
delete cm;
return 0;
}

Related

Select a method as (default) template parameter

I'm developing a container template class. This code needs to interface with existing C code and needs to stay binary compatible, so I can not use i.e. std::vector or similar.
The problem that I have is that it needs to support different allocation strategies, and I don't know how to provide the allocator as a template argument. I created an SSCCE to illustrate how far I got (which of course doesn't compile, because if it would, I wouldn't need to ask this question :)).
#include <iostream>
#include <cstring>
#include <type_traits>
typedef unsigned int uint_t;
typedef signed int int_t;
template <typename T, typename S, typename _allocator = _virtual>
class Container
{
public:
Container(S nItems = 0, S nMaxItems = 0, T *pArray = NULL)
{
mItems = nItems;
mMaxItems = nMaxItems;
mArray = pArray;
}
void adjustMalloc(uint_t nClusterSize)
{
if(mItems == mMaxItems)
{
mArray = (T *)realloc(mArray, (mMaxItems+nClusterSize)*sizeof(T));
mMaxItems += nClusterSize;
}
}
void adjustAligned(uint_t nClusterSize)
{
if(mItems == mMaxItems)
{
mArray = (T *)_aligned_realloc(mArray, (mMaxItems+nClusterSize)*sizeof(T), 16);
mMaxItems += nClusterSize;
}
}
void adjustVirtual(uint_t nClusterSize)
{
if(mItems == mMaxItems)
{
mArray = VirtualAlloc(mArray, (mMaxItems+nClusterSize)*sizeof(T), MEM_RESERVE, PAGE_NOACCESS);
mMaxItems += nClusterSize;
}
}
void adjust(uint_t nClusterSize)
{
if (std::is_same<_allocator>::value == _virtual)
adjustVirtual(nClusterSize);
else if(std::is_same<_allocator>::value == _aligned)
adjustAligned(nClusterSize);
else if(std::is_same<_allocator>::value == _malloc)
adjustMalloc(nClusterSize);
else
{
// Cause a static compiler error, how?
}
}
bool add(T *pItem)
{
if(find(pItem) == NULL)
{
adjust(100);
mItems++;
return true; // added
}
return false;
}
T *find(T *pItem)
{
T *p = mArray;
for(S i = 0; i < mItems; i++, p++)
{
if(*p == *pItem)
return p;
}
return NULL;
}
private:
S mItems;
S mMaxItems;
T *mArray;
};
class Record
{
public:
bool operator==(const Record &oRecord)
{
if(Id != oRecord.Id)
return false;
if(strcmp(Name, oRecord.Name) != 0)
return false;
return true;
}
int Id;
char Name[10+1];
};
int main(int argc, char *argv[])
{
Record rec;
rec.Id = 0;
strcpy(rec.Name, "Test");
Container<Record, uint_t> records; // Default using malloc
records.add(&rec);
if(records.find(&rec) == NULL)
std::cerr << "Not found" << std::endl;
Container<Record, uint_t, _virtual> vrecords; // VirtualAlloc allocator used.
vrecords.add(&rec);
if(records.find(&rec) == NULL)
std::cerr << "Not found" << std::endl;
return 0;
}
I'm using Visual Studio 2010 so it's not 100% C++11.
The VirtualAlloc is provided just as (another) example and will not work as it is shown here.
I found a solution for my problem. However, I get warnings
warning C4127: conditional expression is constant
in the adjust() method for the if(std::is_same... and I was wondering if this is normal or if I can get rid of it, other than disabling it.
#include "stdafx.h"
#include "windows.h"
#include <iostream>
#include <cstring>
#include <type_traits>
#pragma warning (push)
//#pragma warning (disable : 4127)
typedef unsigned int uint_t;
typedef signed int int_t;
typedef struct { const static bool _virtual_allocator = true; } _virtual_type;
typedef struct { const static bool _aligned_allocator = true; } _aligned_type;
typedef struct { const static bool _malloc_allocator = true; } _malloc_type;
template <typename T, typename S, typename _allocator = _aligned_type>
class Container
{
public:
Container(S nItems = 0, S nMaxItems = 0, T *pArray = NULL)
{
mItems = nItems;
mMaxItems = nMaxItems;
mArray = pArray;
}
void adjustMalloc(uint_t nClusterSize)
{
if(mItems == mMaxItems)
{
mArray = (T *)realloc(mArray, (mMaxItems+nClusterSize)*sizeof(T));
mMaxItems += nClusterSize;
}
}
void adjustAligned(uint_t nClusterSize)
{
if(mItems == mMaxItems)
{
mArray = (T *)_aligned_realloc(mArray, (mMaxItems+nClusterSize)*sizeof(T), 16);
mMaxItems += nClusterSize;
}
}
void adjustVirtual(uint_t nClusterSize)
{
if(mItems == mMaxItems)
{
mArray = (T *)VirtualAlloc((LPVOID)mArray, (mMaxItems+nClusterSize)*sizeof(T), MEM_RESERVE, PAGE_NOACCESS);
mMaxItems += nClusterSize;
}
}
void adjust(uint_t nClusterSize)
{
if (std::is_same<_allocator, _virtual_type>::value)
adjustVirtual(nClusterSize);
else if(std::is_same<_allocator, _aligned_type>::value)
adjustAligned(nClusterSize);
else if(std::is_same<_allocator, _malloc_type>::value)
adjustMalloc(nClusterSize);
else
{
// Cause a static compiler error, how?
}
}
bool add(T *pItem)
{
if(find(pItem) == NULL)
{
adjust(100);
mItems++;
return true; // added
}
return false;
}
T *find(T *pItem)
{
T *p = mArray;
for(S i = 0; i < mItems; i++, p++)
{
if(*p == *pItem)
return p;
}
return NULL;
}
private:
S mItems;
S mMaxItems;
T *mArray;
};
#pragma warning (pop)
class Record
{
public:
bool operator==(const Record &oRecord)
{
if(Id != oRecord.Id)
return false;
if(strcmp(Name, oRecord.Name) != 0)
return false;
return true;
}
int Id;
char Name[10+1];
};
int main(int argc, char *argv[])
{
Record rec;
rec.Id = 0;
strcpy(rec.Name, "Test");
Container<Record, uint_t> mrecords;
mrecords.add(&rec);
if(mrecords.find(&rec) == NULL)
std::cerr << "Malloc Not found" << std::endl;
Container<Record, uint_t, _aligned_type> arecords;
arecords.add(&rec);
if(arecords.find(&rec) == NULL)
std::cerr << "Aligned Not found" << std::endl;
Container<Record, uint_t, _virtual_type> vrecords;
vrecords.add(&rec);
if(vrecords.find(&rec) == NULL)
std::cerr << "Virtual Not found" << std::endl;
return 0;
}

Using object of class as an parametr in method

I have method of class Stack, which compares 2 objects of this class:
bool comparison(T &stack) {
if (size == stack.size)
for (int i = 0; i < size; i++) {
if (!this->stackPr[i].comparison(stack.stackPr[i]))
return false;
}
else
return false;
return true;
}
and uses the method of class Time:
bool comparison(Time &time) {
if ((this->hours == time.hours) && (this->minutes == time.minutes) && (this->seconds == time.seconds))
return true;
return false;
When I try to use this comman in main:
bool temp = stack3.comparison(stack4);
MVS underlines |stack4| and shows me the error:
a reference of type "Time &"(non-const qualified) cannot be initialized with a value of type Stack<Time>
How could I handle this problem?
Thanks for your answers :)
There is class Stack:
class Stack {
private:
T *stackPr;
int size;
int top;
public:
//----------------CONSTRUCTORS-----------------
Stack(int n) {
if (n > 0)
size = n;
else
size = 10;
stackPr = new T[size];
top = -1;
}
Stack() {
size = 10;
stackPr = new T[size];
top = -1;
}
Stack(Stack &stack) {
stackPr = new T[stack.size];
size = stack.size;
top = stack.top;
for (int i = 0; i < size; i++)
stackPr[i] = stack.stackPr[i];
}
Stack(T *objs, int sizeMass) {
size = sizeMass;
stackPr = new T[size];
for (int i = 0; i < sizeMass; i++) {
this->push(objs[i]);
}
}
//----------------DESTRUCTOR-------------------
~Stack() {
delete[] stackPr;
}
//-----------------METHODS---------------------
//Add element to stack
void push(T &element) {
if (top == size - 1)
cout << "\nThere's no more place!!!\n";
else {
top++;
stackPr[top] = element;
cout << "\nElement was succesfully pushed\n";
}
}
//Read + Delete
T pop() {
if (top == -1)
cout << "\nStack is empty\n";
else {
T temp = stackPr[top];
stackPr[top] = 0;
top--;
cout << "\nElement was succesfully poped and deleted\n";
return temp;
}
}
//Read
T popup() {
if (top == -1)
cout << "\nStack is empty\n";
else {
cout << "\nElement was succesfully popped\n";
return stackPr[top];
}
}
//Comparison of 2 stacks
bool comparison(T &stack) {
if (size == stack.size)
for (int i = 0; i < size; i++) {
if (!this->stackPr[i].comparison(stack.stackPr[i]))
return false;
}
else
return false;
return true;
}
};
Try this, in your Stack class
change:
bool comparison(T &stack) {
for this:
bool comparison(Stack<T> &stack) {
First of all, abandon this comparison function, it hinders your code, use == instead.
Secondly, use const Stack<T> in your comparison function.
And finally, use auto to deduce the type of the variables.
Here is an example that shows the basics of what I just wrote:
#include <iostream>
using namespace std;
struct Time
{
bool operator==(const Time& time)
{
return true;// adjust it with your own needs.
}
};
template<typename T>
struct Stack
{
T val;
Stack(T& val_): val(val_) {}
bool operator==(const Stack<T>& stack)
{
return this->val == stack.val; // here is your business logic of comparison
}
};
int main()
{
Time t1;
Time t2;
Stack<Time> myStack1(t1);
Stack<Time> myStack2(t2);
auto temp = myStack1 == myStack2;
cout << temp << endl;
return 0;
}

Invalid allocation size. Trying to merge Array Sorted List

I have to develop two functions. One is an application level function that merges two sortedlists implemented using dynamic arrays. The other is the same except its supposed to be a member function. I get invalid allocation size. When I trace the function it successfully returns without an error buy as soon as I reach the original calling code I get the error. Here is the code for both functions.
Application level function:
ArraySortedType& merge(const ArraySortedType& list1, const ArraySortedType& list2)
{
ItemType temp;
ArraySortedType ret, list1Copy=list1, list2Copy=list2;
list1Copy.ResetList();
while (list1Copy.GetNextItem(temp) == Success)
ret.InsertItem(temp);
list2Copy.ResetList();
while (list2Copy.GetNextItem(temp) == Success)
ret.InsertItem(temp);
return ret;
}
Member function:
ArraySortedType& ArraySortedType::merge(const ArraySortedType& list)
{
ArraySortedType s, copy = list;
ItemType temp;
copy.ResetList();
while (copy.GetNextItem(temp) == Success)
s.InsertItem(temp);
for (int k = 0; k < length; k++)
s.InsertItem(info[k]);
return s;
}
Code where I call functions:
ArraySortedType u = merge(s, n);
//ArraySortedType k = merge(s, n);
cout << "Length of u is: " << u.LengthIs() << endl;
// cout << "Length of k is: " << k.LengthIs() << endl;
Even the commented out code doesn't work.
Also there is alot of code for implementing the ArraySortedType that I've left out because I think it's unnecessary. Most of it was already given with the lab. InsertItem was implemented by me and is used quite a bit so I'll include it here:
Error_Code ArraySortedType::InsertItem ( ItemType item)
{
if(!length)
{
info[0] = item;
length++;
return Success;
}
for(int i=0;i<=length;i++)
{
if(info[i].ComparedTo(item) != LESS || i==length)
{
for(int j=length;j>i;j--)
info[j] = info[j-1];
info[i]=item;
length++;
return Success;
}
}
return Fail;
}
GetNextItem() and ResetList() were already given so they cant be the problem so I'll leave them out but just tell me if they are required.
I've traced both of them and googled quite a bit but this problem has left me scratching my head. Any help would be appreciated.
EDIT:
I guess the implementation of ArraySortedList will be necessary. Here it is. Guess I don't really expect anyone to actually go through it though:
//ArraySortedType.cpp
#include "ArraySortedType.h"
ArraySortedType::ArraySortedType (int max_items)
{
length =0;
MAX_ITEMS = max_items;
currentPos =-1;
try
{
info = new ItemType[MAX_ITEMS];
}
catch(std::bad_alloc exception)
{
//Severe problem, do not keep program running
cout <<"Memory full "<< endl;
exit(1);
}
}
ArraySortedType::~ArraySortedType()
{
delete [] info;
info = NULL;
}
void ArraySortedType::ResetList ( )
{
currentPos = -1;
}
bool ArraySortedType::IsFull ( ) const
{
if(length == MAX_ITEMS)
{
try
{//Check if memory allocation is fine
ItemType * temp = new ItemType[2*MAX_ITEMS];
delete [] temp;
return false;
}
catch(std::bad_alloc exception)
{
return true;
}
}
return false;
}
bool ArraySortedType::IsEmpty () const {
return (length==0);
}
int ArraySortedType:: LengthIs () const {
return length;
}
Error_Code ArraySortedType::DeleteItem ( ItemType item ) {
int location = 0;
while ((item.ComparedTo(info[location]) != EQUAL ) && location < length)
location++;
if (location == length) return Fail;
info[location] = info[length - 1];
length--;
return Success;
}
Error_Code ArraySortedType::GetNextItem (ItemType& item) {
currentPos++;
if( currentPos == length ) return Fail;
item = info[currentPos] ;
return Success;
}
ArraySortedType::ArraySortedType(const ArraySortedType & ust)
{
MAX_ITEMS =ust.MAX_ITEMS;
length=ust.length;
try
{
info = new ItemType[MAX_ITEMS];
}
catch(std::bad_alloc exception)
{
//Severe problem, do not keep program running
cout <<"Memory full "<< endl;
exit(1);
}
for(int i=0;i<length; i++)
info[i] = ust.info[i];
currentPos=ust.currentPos;
}
ArraySortedType& ArraySortedType::operator=(const ArraySortedType & ust)
{
if(this == &ust) return *this;
if(MAX_ITEMS !=ust.MAX_ITEMS)
{
delete [] info;
MAX_ITEMS = ust.MAX_ITEMS;
try
{
info = new ItemType[MAX_ITEMS];
}
catch(std::bad_alloc exception)
{
//Severe problem, do not keep program running
cout <<"Memory full "<< endl;
exit(1);
}
}
currentPos=ust.currentPos;
length=ust.length;
for(int i=0;i<length; i++)
info[i] = ust.info[i];
return *this;
}
//Assumes that an employee has unique ID
bool ArraySortedType::operator==(const ArraySortedType & ust)
{
if(this == &ust) return true;
if(length!=ust.length) return false;
if(currentPos!=ust.currentPos) return false;
for(int i=0;i<length; i++)
if(info[i].ComparedTo(ust.info[i])!=EQUAL) return false;
return true;
}
Error_Code ArraySortedType::InsertItem ( ItemType item)
{
if(!length)
{
info[0] = item;
length++;
return Success;
}
for(int i=0;i<=length;i++)
{
if(info[i].ComparedTo(item) != LESS || i==length)
{
for(int j=length;j>i;j--)
info[j] = info[j-1];
info[i]=item;
length++;
return Success;
}
}
return Fail;
}
Error_Code ArraySortedType::RetrieveItem (ItemType& item , bool& found)
{
found = false;
int front = 0, back = length - 1, midpoint=(length-1)/2;
while (front<=back)
{
switch (info[midpoint].ComparedTo(item))
{
case EQUAL:
item = info[midpoint];
found = true;
break;
case LESS:
front = midpoint + 1;
break;
case GREATER:
back = midpoint - 1;
break;
}
if (found)
break;
midpoint = ((back - front) / 2 + front);
}
return Fail;
}
Error_Code ArraySortedType::Delete(ItemType startKey, ItemType endKey)
{
bool startFound = false, endFound = false;
int numberDeleted=0, startLocation;
bool deleting = false;
for (int i = 0; i < length; i++)
{
if (info[i].ComparedTo(startKey) == EQUAL)
{
startLocation = i;
deleting = true;
startFound = true;
}
if (deleting)
numberDeleted++;
if (info[i].ComparedTo(endKey) == EQUAL)
{
deleting = false;
endFound = true;
}
}
if (!(startFound || endFound))
return Fail;
length -= numberDeleted;
for (int i = startLocation; i < length; i++)
info[i] = info[i + startLocation];
return Success;
}
ArraySortedType ArraySortedType::RetrieveItemsInRange(ItemType startKey, ItemType endKey)
{
ArraySortedType r;
bool startFound = false, endFound = false;
int numberDeleted = 0, startLocation;
bool retrieving = false;
for (int i = 0; i < length; i++)
{
if (info[i].ComparedTo(startKey) == EQUAL)
{
startLocation = i;
retrieving = true;
startFound = true;
}
if (retrieving)
r.InsertItem(info[i]);
if (info[i].ComparedTo(endKey) == EQUAL)
{
retrieving = false;
endFound = true;
}
}
return r;
}
ArraySortedType& ArraySortedType::merge(const ArraySortedType& list)
{
ArraySortedType s, copy = list;
ItemType temp;
copy.ResetList();
while (copy.GetNextItem(temp) == Success)
s.InsertItem(temp);
for (int k = 0; k < length; k++)
s.InsertItem(info[k]);
return s;
}
ItemType is defined as a class Employee. I really hope I don't have to include it here as well. The class Employee has a compareTo class defined as follows:
RelationType Employee::ComparedTo(const Employee & e)
{
if(eid < e.eid) return LESS;
else if(eid == e.eid) return EQUAL;
else return GREATER;
}
There is a an enum called relation type that has values LESS, EQUAL and GREATER.

std::vector::resize results in a crash in a template class

Here's the code :
The place where it crashed is marked with a comment(//////crash).
I don't know what results in the problem.
After I print the size of data got from file,It shows '1' means that the array should only contains 1 element. So it seems that there's no 'bad_allocate error' ...
Could you guys help me ? I would appreciate your kindly help very much. :)
#include<stdio.h>
#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<algorithm>
#include<string.h>
#include<type_traits>
using namespace std;
bool read_int(int& val,FILE*& fp)
{
if(fp == nullptr)
return false;
fread(&val,sizeof(int),1,fp);
return true;
}
bool write_int(int val,FILE*& fp)
{
if(fp == nullptr)
{
return false;
}
fwrite(&val,sizeof(int),1,fp);
return true;
}
struct SANOBJ
{
char path[128];
char nickname[40];
SANOBJ(const char* _p = nullptr,const char* _n = nullptr)
{
if(_p == nullptr || _n == nullptr)
*this = {};
int m = strlen(_p),n = strlen(_n);
if(m < 128) strcpy(path,_p);
if(n < 40) strcpy(nickname,_n);
}
~SANOBJ(){}
SANOBJ(const SANOBJ& other)
{
memcpy(path,other.path,sizeof(char) * 128);
memcpy(nickname,other.nickname,sizeof(char) * 40);
}
bool operator < (const SANOBJ& other) const
{
return string(path) < string(other.path);
}
bool operator == (const SANOBJ& other) const
{
return (strcmp(other.path,path) == 0);
}
};
template <typename source_type> //the 'source_type' type need to have the member 'int m_index'
class FrameQueue
{
public:
FrameQueue() //fill the 1st frame automatically
{
source_type new_node;
new_node.m_index = 0;
m_data.push_back(new_node);
}
FrameQueue(const FrameQueue& other)
{
m_data = other.m_data;
}
bool AddFrame(const source_type& other) // keeps an ascending order
{
int index = _binary_search(other);
if(index != -1)
{
return false;
}
m_data.insert(std::upper_bound(m_data.begin(),m_data.end(),other,
[](const source_type& a,const source_type& b)->bool const{return a.m_index < b.m_index;}
),other);
return true;
}
bool DeleteFrameByElemIndex(int elemIndex) //delete frame according to the index of frame in the queue
{
if(elemIndex < 0)
return false;
if(elemIndex >= m_data.size())
return false;
typename std::vector<source_type>::iterator it ;
it = m_data.begin() + elemIndex;
it = m_data.erase(it);
return true;
}
bool DeleteFrameByFrameIndex(int frameIndex)
{
source_type node = {};
node.m_index = frameIndex;
int index = _binary_search(node);
if(index == -1)
{
return false;
}
typename std::vector<source_type>::iterator it;
it = m_data.begin() + index;
it = m_data.erase(it);
return true;
}
bool Clear() // There would always be a single frame
{
source_type new_node = {};
new_node.m_index = 0;
m_data.clear();
m_data.push_back(new_node);
return true;
}
bool WriteFile(FILE*& fp)
{
if(fp == nullptr)
return false;
bool result = write_int(m_data.size(),fp);
if(result == false)
return false;
fwrite(&(m_data[0]),sizeof(source_type),m_data.size(),fp);
return true;
}
bool ReadFile(FILE*& fp)
{
if(fp == nullptr)
return false;
int data_size;
bool result = read_int(data_size,fp);
if(result == false)
return false;
if(data_size > 0)
{
m_data.resize(data_size);
fread(&(m_data[0]),sizeof(source_type),data_size,fp);
}
return true;
}
private:
int _binary_search(source_type target)
{
int l = 0,r = (int)m_data.size() - 1,mid;
while(l<=r)
{
mid = (l + r) / 2;
if(m_data[l].m_index == target.m_index)
{
return l;
}
if(m_data[r].m_index == target.m_index)
{
return r;
}
if(m_data[mid].m_index == target.m_index)
{
return mid;
}
if(m_data[mid].m_index > target.m_index)
{
r = mid - 1;
}
else
{
l = mid + 1;
}
}
return -1;
}
public:
vector<source_type> m_data;
};
template<typename source_type>
class UniqueSource
{
public:
UniqueSource(){}
~UniqueSource(){}
bool Add(const source_type& other)//return false when insert failed,otherwise return true
{
if(m_map_source_to_index.find(other) == m_map_source_to_index.end())
{
int map_size = m_map_source_to_index.size();
m_data.push_back(other);
m_map_source_to_index.insert(pair<source_type,int>(other,map_size));
m_result.push_back(map_size);
return true;
}
else
{
m_result.push_back(m_map_source_to_index[other]);
return true;
}
return false;
}
bool Delete(int elemIndex) // delete the elem by elem Index,If succeed ,return true,otherwise return false
{
if(elemIndex < 0)
return false;
if(elemIndex >= m_data.size())
return false;
typename std::map<source_type,int>::iterator mit;
typename std::vector<source_type>::iterator vit;
for(mit = m_map_source_to_index.begin();mit!=m_map_source_to_index.end();++mit)
{
m_map_source_to_index.erase(mit);
}
vit = m_data.begin() + elemIndex;
m_data.erase(vit);
return true;
}
bool Clear()
{
m_map_source_to_index.clear();
m_data.clear();
m_result.clear();
return true;
}
bool WriteFile(FILE*& fp)
{
if(fp == nullptr)
return false;
bool result = write_int(m_data.size(),fp);
if(result == false)
return false;
if(m_data.size() > 0)
fwrite(&(m_data[0]),sizeof(source_type),m_data.size(),fp);
result = write_int(m_result.size(),fp);
if(result == false)
return false;
if(m_result.size() > 0)
fwrite(&(m_result[0]),sizeof(int),m_result.size(),fp);
return true;
}
bool ReadFile(FILE*& fp)
{
if(fp == nullptr)
return false;
Clear();
int data_size;
read_int(data_size,fp);
if(data_size > 0)
{
printf("[%d]",data_size);
m_data.resize(data_size); /////////////////Crash!!!!!!!!!!!!
printf("Resize Ok\r\n");
fread(&(m_data[0]),sizeof(source_type),data_size,fp);
}
read_int(data_size,fp);
printf("[%d]",data_size);
if(data_size > 0)
{
m_result.resize(data_size);
fread(&(m_result[0]),sizeof(int),data_size,fp);
}
return true;
}
//private:
map<source_type,int> m_map_source_to_index;
vector<source_type> m_data;
vector<int> m_result; //the index I want
};
int main()
{
UniqueSource<SANOBJ> m;
SANOBJ t = {"123","456"};
m.Add(t);
printf("Added\r\n");
FILE* fp = nullptr;
fp = fopen("test.b","wb");
if(fp == nullptr)
{
printf("Failed...\r\n");
}
bool ret = false;
ret = m.WriteFile(fp);
if(ret)
{
printf("Writed!\r\n");
fclose(fp);
}
fp = fopen("test.b","rb");
if(fp == nullptr)
{
printf("Failed...\r\n");
}
ret = m.ReadFile(fp);
fclose(fp);
printf("Readed\r\n");
for(int i=0;i<m.m_data.size();i++)
printf("%s %s\r\n",m.m_data[i].path,m.m_data[i].nickname);
return 0;
}
*this = {} default-constructs a new SANOBJ instance and then assigns it to *this. This would normally be OK, but here you are calling it from the SANOBJ default constructor (making the logic being something like "to default-construct a SANOBJ, default-construct a SANOBJ and then assign its value to myself"), leading to infinite recursion and eventually a stack overflow.
Sidenote: The copy constructor is not needed.
Yes. The problem is is with *this = {}
If I were you, I'd rewrite SANOBJ constructor like this (this is a rough code and you may need to slightly modify it if you wish)
SANOBJ(const char* _p = nullptr,const char* _n = nullptr)
{
if (( _p != nullptr ) && ((strlen(_p) < 128)))
strcpy(path,_p);
if (( _n != nullptr ) && ((strlen(_n) < 40)))
strcpy(nickname,_n);
}
It'll resolve the problem.
Naturally, I don't play with *this (not this).
If you want to be sure that the member variables are empty (char path[128] and char nickname[40])
set at the beginning of the constructor something like:
path[0] = '\0';
nickname[0] = '\0';
Or use something like on constructor:
SANOBJ(const char* _p = nullptr,const char* _n = nullptr)
: path(), nickname()
{
}
But don't use *this= {}

deep copying a struct

I have a struct defined as follows
struct VariableList
{
void Add(simple_instr* instr)
{
//PrintOpcode(instr);
switch(instr->opcode)
{
case STR_OP:
case MCPY_OP:
Add(instr->u.base.src1);
Add(instr->u.base.src2);
break;
case LDC_OP:
Add(instr->u.ldc.dst);
break;
case BTRUE_OP:
case BFALSE_OP:
Add(instr->u.bj.src);
break;
case CALL_OP:
if (instr->u.call.dst != NO_REGISTER)
{
Add(instr->u.call.dst);
}
Add(instr->u.call.proc);
for (int i = 0; i < instr->u.call.nargs; i++)
{
Add(instr->u.call.args[i]);
}
break;
case MBR_OP:
Add(instr->u.mbr.src);
break;
case RET_OP:
if (instr->u.base.src1 != NO_REGISTER)
Add(instr->u.base.src1);
break;
case CVT_OP:
case CPY_OP:
case NEG_OP:
case NOT_OP:
case LOAD_OP:
Add(instr->u.base.dst);
Add(instr->u.base.src1);
break;
case LABEL_OP:
case JMP_OP:
break;
default:
Add(instr->u.base.dst);
Add(instr->u.base.src1);
Add(instr->u.base.src2);
break;
}
}
void Add(Variable var)
{
variableList.push_back(var);
}
void RemoveDuplicates()
{
if (variableList.size() > 0)
{
variableList.erase(unique(variableList.begin(), variableList.end()), variableList.end());
currentID = variableList.size();
}
}
VariableList()
{
currentID = 0;
dynamicallyCreated = false;
}
VariableList(VariableList& varList, bool setLiveness = false, bool LiveVal = false)
{
currentID = 0;
for (int i = 0; i < varList.size(); i++)
{
Variable* var = new Variable(varList[i]);
if (setLiveness)
{
var->isLive = LiveVal;
}
variableList.push_back(*var);
}
dynamicallyCreated = variableList.size() > 0;
}
Variable& operator[] (int i)
{
return variableList[i];
}
int size()
{
return variableList.size();
}
vector<Variable>::iterator begin()
{
return variableList.begin();
}
vector<Variable>::iterator end()
{
return variableList.end();
}
bool CompareLiveness(VariableList &var)
{
if(variableList.size() != var.size())
{
return false;
}
for (int i = 0; i < variableList.size(); i++)
{
if(variableList[i].isLive != var[i].isLive)
return false;
}
return true;
}
~VariableList()
{
if(dynamicallyCreated)
{
for (vector<Variable>::iterator it = variableList.begin(); it < variableList.end(); ++it)
{
//delete (&it);
}
}
}
protected:
int currentID;
vector<Variable> variableList;
bool dynamicallyCreated;
void Add(simple_reg* reg, bool checkForDuplicates = false)
{
if (reg == null)
{
cout << "null detected" << endl;
return;
}
if (reg->kind == PSEUDO_REG)
{
if (!checkForDuplicates || (checkForDuplicates && find(variableList.begin(), variableList.end(), reg->num) != variableList.end()))
{
cout << "Adding... Reg " << reg->num << endl;
Variable* var = new Variable(reg->num, currentID);
variableList.push_back(*var);
currentID++;
}
}
}
};
I'd like to be able to do a statement like this
VariableList varsIn(Variables, true, false);
that will create a deep copy and allow me to change a few properties. As you can see in my struct, I'm currently attempting to do this using
VariableList(VariableList& varList, bool setLiveness = false, bool LiveVal = false)
{
currentID = 0;
for (int i = 0; i < varList.size(); i++)
{
Variable* var = new Variable(varList[i]);
if (setLiveness)
{
var->isLive = LiveVal;
}
variableList.push_back(*var);
}
dynamicallyCreated = variableList.size() > 0;
}
I don't think this is the right way to do it though. What's the proper way to do this sort of copying? Is there a way to do it without using new? For reference, the Variable struct is as follows
struct Variable
{
int id;
int num;
bool isLive;
simple_op opcode;
Variable()
{
id = 0;
num = 0;
opcode = NOP_OP;
vClass = Basic;
isLive = false;
}
Variable(int _num, int _id = 0, simple_op _op = NOP_OP)
{
id = _id;
num = _num;
opcode = _op;
vClass = Basic;
isLive = false;
}
VariableClass GetClass()
{
return vClass;
}
bool operator==(const Variable &var) const
{
return num == var.num;
}
bool operator==(const int &x) const
{
return x == num;
}
protected:
VariableClass vClass;
};
VariableClass and simple_op are enums
Thanks in advance
Your code is not only doing dynamic allocation unnecessarily, it's also leaking Variable instances everywhere. Just use an automatic variable, push_back will make a copy:
VariableList(VariableList& varList, bool setLiveness = false, bool LiveVal = false)
{
currentID = 0;
for (int i = 0; i < varList.size(); i++)
{
Variable var(varList[i]);
if (setLiveness)
{
var.isLive = LiveVal;
}
variableList.push_back(var);
}
}
And take out the destructor, you can't delete the elements owned by the vector. If they pointed somewhere, sure, but you're not storing pointers.
Also, here's an even better way:
VariableList(VariableList& other, bool setLiveness = false, bool LiveVal = false)
: currentID(0)
, variableList(other.variableList)
{
if (setLiveness) {
for( int i = 0; i < size(); i++ )
variableList[i].isLive = LiveVal;
}
}