I get a segmentation fault when i try to insert into my map.
The function looks something like this:
void add(std::string id, std::string name)
{
Asset asset(nullptr, false, name);
mAssets.insert(std::make_pair<std::string, Asset>(id,asset)); <-- This line gives segfault
}
mAssets is simply declared
std::map<assetID, Asset> mAssets;
And the Asset class is (sloppy) declared like this:
class Asset
{
public:
Asset(T* a, bool l, std::string f) : asset(a), loaded(l), filename(f)
{
}
Asset(const Asset& copy)
{
loaded = copy.loaded;
filename = copy.filename;
asset = new T();
*asset = *copy.asset;
}
~Asset()
{
delete asset;
}
Asset& operator=(const Asset& other)
{
Asset temp(other);
loaded = temp.loaded;
filename = temp.filename;
std::swap(asset,temp.asset);
return *this;
}
T* asset;
bool loaded;
std::string filename;
};
Your problem is here in your copy constructor:
asset = new T();
*asset = *copy.asset;
I will leave it to you to work out why...
On your copy constructor you are derefferencing a null pointer:
*asset = *copy.asset
from
Asset asset(nullptr, false, name);
Verify your pointers asigments and avoid dereferencing null pointers:
Asset(const Asset& copy)
{
loaded = copy.loaded;
filename = copy.filename;
if (copy.asset)
{
asset = new T(); // better may be asset = new T(copy)
*asset = *copy.asset;
}
else
{
asset = nullptr
}
}
*asset = *copy.asset; //you should check whether asset is NULL or not then check for asset
This is how your code will work:
#include <iostream>
#include <map>
using namespace std;
template<class T>
class Asset
{
public:
Asset(T* a, bool l, std::string f) : asset(a), loaded(l), filename(f)
{
}
Asset(const Asset& copy)
{
cout<<"copy"<<endl;
loaded = copy.loaded;
filename = copy.filename;
asset = new T();
if(© != NULL)
{
if(copy.asset != NULL)
*asset = *(copy.asset);
}
}
~Asset()
{
delete asset;
}
Asset& operator=(const Asset& other)
{
Asset temp(other);
loaded = temp.loaded;
filename = temp.filename;
std::swap(asset,temp.asset);
return *this;
}
T* asset;
bool loaded;
std::string filename;
};
std::map <string,Asset<int> > mAssets;
void add(std::string id, std::string name)
{
Asset<int> asset(NULL, false, name);
mAssets.insert(std::make_pair<std::string, Asset<int> >(id,asset)); //<-- This line gives segfault
}
int main()
{
add("1","hi");
cout<<"run"<<endl;
}
Related
For example, I create a singleTon lock class. Then I use the locker whatever I want, for example another singleTon
class SIN
{
public:
static SIN& getSIN()
{
static SIN *sin = new SIN;
return *sin;
}
void insertMap(const int& id,const string& str)
{
locker::getLocker().lock();
subMap[id] = str;
locker::getLocker().unlock();
return;
}
string getStr(const int& id)
{
string str = "";
locker::getLocker().lock();
if(subMap.find(id) != subMap.end()){
str = subMap[id];
}
locker::getLocker().unlock();
return str;
}
private:
SIN(){}
SIN(const SIN&) = delete;
SIN& operator=(const SIN&) = delete;
private:
map<int,string> subMap;
}
I don't find this usage in network, will there be any potential problems during using?
I want to delete every element at a certain index (that corresponds to a certain content), but I'm getting a segmentation fault... This is the structure of my code and the method deleteRecord is what I've tried but doesn't work:
class Tab {
public:
Tab();
~Tab() {};
bool colIsPresent(const string & col_name);
template <typename S> void deleteRecord(S & content, const string & col_name) {
int delete_pos;
if (!this->colIsPresent(col_name)) return;
const auto & it_columns = _columns.find(col_name);
if (it_columns != _columns.end()) {
auto ci = dynamic_cast<ColumnImpl<S> *>(it_columns->second.get());
if (ci != nullptr) {
for (int i = 0; i < ci->getData().size(); i++) {
if (ci->getData()[i] == content) {
delete_pos = i;
}
for (auto & it_columns_2 : _columns) {
auto ci2 = dynamic_cast<ColumnImpl<S> *>(it_columns_2.second.get());
ci2->getData().erase(ci2->getData().begin() + delete_pos);
}
}
}
}
}
private:
map<string, shared_ptr<Column>> _columns;
};
template <typename T> class ColumnImpl : public Column {
public:
ColumnImpl() : Column() {}
ColumnImpl(const T& to_set);
vector<T> & getData() { return _data; }
protected:
vector<T> _data;
};
class Column {
public:
Column();
virtual ~Column() {};
virtual string getType() = 0;
};
class Database {
public:
Database();
~Database();
bool tabIsPresent(const string & tab_name);
template <typename S> void deleteRecordFromTab(const string & tab_name, S & content, const string & col_name) {
const auto & it_target_tab = _tables.find(tab_name);
it_target_tab->second.deleteRecord(content, col_name);
}
private:
map<string, Tab> _tables;
};
Reproducible example:
Database data_base;
string tab = "EX_TAB", str1 = "STR_EX1", str2 = "STR_EX2", age = "AGE", name = "NAME", integer = "INT", text = "TEXT";
int a = 17, b = 18;
data_base.createNewTable(tab);
data_base.addColumnToTab(tab, age, integer);
data_base.addColumnToTab(tab, name, text);
data_base.addElemToColOfTab(tab, age, a);
data_base.addElemToColOfTab(tab, age, b);
data_base.addElemToColOfTab(tab, name, str1);
data_base.addElemToColOfTab(tab, name, str2);
data_base.deleteRecordFromTab(tab, str1, name);
// createNewTable creates a new table
// addColumnToTab adds a new column of the right type to _columns
// addElemToColumnOfTab adds an element to the targeted column
I have a assignment where I'm suppose to build template using these specifications.
ISet is a container that holds values of a certain where order doesn't matter and
which does not allow duplicates (or multiples).
A dynamically allocated array of type T should be used as an internal data structure for the Set.
The Set should inherit from the ISet interface below - this must not be modified:
template <typename T>
class ISet
{
public:
virtual bool insert (T element) = 0;
virtual bool remove (T element) = 0;
virtual int size () const = 0;
};
• insert (T element): adds elements to the set and returns true provided that
the element is not already present in the quantity (in which case the element is not added and false is returned).
• remove (T element): removes elements from the set and returns true.
If the element is missing in the quantity, false returns.
• size (): returns the number of elements in the set.
In addition to the member functions, you must implement constructor, destructor, copy constructor
and assignment operator.
And so far have I come up with this code:
#pragma once
#include <string>
#include <iostream>
using namespace std;
template <class T>
class ISet
{
public:
virtual bool insert(T element) = 0;
virtual bool remove(T element) = 0;
virtual int size() const = 0;
};
#pragma once
#include "ISet.h"
template <class T>
class Set : public ISet<T>
{
public:
Set(string name);
~Set();
Set(const Set &origin);
//Set& operator=(const Set &origin);
bool insert(T element);
bool remove(T element);
int size()const;
private:
string name;
T *arr;
int cap, nrOfElement;
};
template<class T>
Set<T>::Set(string name)
{
this->name = name;
this->cap = 10;
this->nrOfElement = 0;
this->arr = new T[this->cap];
}
template<class T>
Set<T>::~Set()
{
delete[] arr;
}
template<class T>
Set<T>::Set(const Set & origin)
{
this->nrOfElement = origin.nrOfElement;
this->cap = origin.cap;
arr = new T*[cap];
for (int i = 0; i < nrOfElement; i++)
{
arr[i] = origin.arr[i];
}
}
template<class T>
bool Set<T>::insert(T element)
{
bool found = false;
if (nrOfElement == 0)
{
this->arr[0] = element;
this->nrOfElement++;
}
else
{
for (int i = 0; i < this->nrOfElement; i++)
{
if (this->arr[i] == element)
{
i = this->nrOfElement;
found = true;
}
}
if (found == false)
{
this->arr[nrOfElement++] = element;
}
}
return found;
}
template<class T>
bool Set<T>::remove(T element)
{
bool removed = false;
for (int i = 0; i < this->nrOfElement; i++)
{
if (this->arr[i] == element)
{
this->arr[i] = this->arr[nrOfElement];
nrOfElement--;
removed = true;
}
}
return removed;
}
template<class T>
int Set<T>::size() const
{
return this->nrOfElement;
}
And my problems starts when I start to test this code by adding the different data-type we are suppose to test the template against.
#include "Set.h"
#include "ISet.h"
#include "Runner.h"
int main()
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
Set<string> test("test");
test.insert("lol");
cout << test.size();
test.remove("lol");
cout << test.size();
Set<Runner> test2("test");
getchar();
return 0;
}
Getting the error saying that "No operator found which takes a left-hand operand type of 'Runner'. So I have to create a operator== that handles this but don't know?
Runner class looks like this:
#pragma once
#include "Competitor.h"
#include <string>
using namespace std;
class Runner : public Competitor
{
public:
Runner();
Runner(string firstName, string lastName, int startNr);
~Runner();
void addResult(int resultTime);
int getResult() const;
string toString() const;
Runner *clone() const;
private:
int resultTime;
};
#include "Runner.h"
Runner::Runner()
{
this->resultTime = 0;
}
Runner::Runner(string firstName, string lastName, int startNr) : Competitor(firstName, lastName, startNr)
{
this->resultTime = 0;
}
Runner::~Runner()
{
}
void Runner::addResult(int resultTime)
{
this->resultTime = resultTime;
}
int Runner::getResult() const
{
return this->resultTime;
}
string Runner::toString() const
{
return (to_string(this->resultTime) + " sec");
}
Runner * Runner::clone() const
{
return new Runner(*this);
}
How do I build a operator== that will work for this?
You need to add operator== to the Runner class:
bool operator==(const Runner& other) const;
I am learning about dynamic allocation of memory in C++. I've come across a problem for which I can't seem to find an answer.
In my program, I have a struct which goes like this:
struct Friend
{
string name = "";
int daysSinceContact = 0;
};
struct User
{
string name = "";
string password = "";
int numberOfFriends = 0;
Friend *friends = new Friend[numberOfFriends];
};
In my program, I create an array of users, which goes something like this:
int numberOfUsers = 5;
User *usersInformation = new User[numberOfUsers];
And it works fine. But I'd like to be able to add more friends to a chosen user, for example:
int nFriends = usersInformation[0].numberOfFriends;
usersInformation[0].numberOfFriends++;
usersInformation[0].friends[nFriends-1].name = "John";
usersInformation[0].friends[nFriends-1].daysSinceContact = 2;
I'm guessing that I should use a buffer to copy the information from the array containing information about friends, and do something like this:
delete[] usersInformation[0].friends[];
usersInformation[0].numberOfFriends++;
usersInformation[0].friends = new Friend[numberOfFriends];
And then copy it back and add information about the new friend. But when I've tried, it didn't work.
Do you have any tips?
The correct solution is to not use a manual array at all, use the STL's std::vector container instead, eg:
#include <vector>
#include <string>
struct Friend
{
std::string name = "";
int daysSinceContact = 0;
};
struct User
{
std::string name = "";
std::string password = "";
std::vector<Friend> friends;
};
...
std::vector<User> usersInformation(5);
...
Friend newFriend;
newFriend.name = "John";
newFriend.daysSinceContact = 2;
usersInformation[0].friends.push_back(newFriend);
// Or simpler:
usersInformation[0].friends.emplace_back(Friend{"John", 2});
That being said, if you really want to manage the array manually, you need to do something more like this instead (which includes implementing the Rule of Five to prevent corrupting and leaking memory):
#include <string>
struct Friend
{
std::string name = "";
int daysSinceContact = 0;
};
struct User
{
std::string name = "";
std::string password = "";
int numberOfFriends = 0;
Friend *friends = new Friend[numberOfFriends];
// default constructor (nothing extra that isn't already done above)
User() = default;
// copy constructor
User(const User &src) :
name(src.name),
password(src.password),
numberOfFriends(src.numberOfFriends),
friends(new Friend[numberOfFriends])
{
for(int i = 0; i < numberOfFriends; ++i)
friends[i] = src.friends[i];
}
// move constructor
User(User &&src) :
name(std::move(src.name)),
password(std::move(src.password)),
numberOfFriends(numberOfFriends),
friends(src.friends)
{
src.friends = nullptr;
src.numberOfFriends = 0;
}
// destructor
~User()
{
delete[] friends;
}
// copy assignment operator
User& operator=(const User &src)
{
if (this != &src)
{
Friend *newFriends = new Friend[src.numberOfFriends];
for(int i = 0; i < src.numberOfFriends; ++i)
newFriends[i] = src.friends[i];
name = src.name;
password = src.password;
delete[] friends;
friends = newFriends;
numberOfFriends = src.numberOfFriends;
}
return *this;
}
// move assignment operator
User& operator=(User &&src)
{
name := std::move(src.name);
password = std::move(src.password);
Friend *oldFriends = friends;
friends = src.friends;
src.friends = oldFriends;
int oldNumber = numberOfFriends;
numberOfFriends = src.numberOfFriends;
src.numberOfFriends = oldNumber;
return *this;
}
// addition helper
void addFriend(const std::string &name, int daysSinceContact = 0)
{
Friend *newFriends = new Friend[numberOfFriends + 1];
for(int i < 0; i < numberOfFriends; ++i)
newFriends[i] = friends[i];
newFriends[numberOfFriends].name = name;
newFriends[numberOfFriends].daysSinceContact = daysSinceContact;
delete[] friends;
friends = newFriends;
++numberOfFriends;
}
};
Or this, which is slightly safer in terms of memory management:
#include <string>
#include <utility>
#include <algorithm>
struct Friend
{
std::string name = "";
int daysSinceContact = 0;
};
struct User
{
std::string name = "";
std::string password = "";
int numberOfFriends = 0;
Friend *friends = new Friend[numberOfFriends];
// default constructor (nothing extra that isn't already done above)
User() = default;
// initializing constructor
User(int initialCapacity) :
friends(new Friend[initialCapacity])
{
}
// copy constructor
User(const User &src) :
User(src.numberOfFriends),
name(src.name),
password(src.password),
numberOfFriends(src.numberOfFriends)
{
std::copy(src.friends, src.friends + src.numberOfFriends, friends);
}
// move constructor
User(User &&src) :
name(std::move(src.name)),
password(std::move(src.password)),
numberOfFriends(0),
friends(nullptr)
{
std::swap(friends, src.friends);
std::swap(numberOfFriends, src.numberOfFriends);
}
// destructor
~User()
{
delete[] friends;
}
// copy assignment operator
User& operator=(const User &src)
{
if (this != &src)
User(src).swap(*this);
return *this;
}
// move assignment operator
User& operator=(User &&src)
{
src.swap(*this);
return *this;
}
// swap helper
void swap(User &other)
{
std::swap(name, other.name);
std::swap(password, other.password);
std::swap(numberOfFriends, other.numberOfFriends);
std::swap(friends, other.friends);
}
// addition helper
void addFriend(const std::string &name, int daysSinceContact = 0)
{
User temp(numberOfFriends + 1);
std::copy(friends, friends + numberOfFriends, temp.friends);
temp.friends[numberOfFriends] = Friend{name, daysSinceContact};
std::swap(friends, temp.friends);
++numberOfFriends;
}
};
Either way, then you can do this:
User *usersInformation = new User[5];
...
usersInformation[0].addFriend("John", 2);
...
delete[] usersInformation;
I'm having a little trouble with the following:
I'm writing a map abstract data type for some coursework & I've come across a problem whilst trying to assign an object of my class (MapEntry - below) to an array of the same type in the class MapADT. It tells me that:
Error 1 error C2679: binary '=' : no operator found which takes a right-hand operand of type 'MapEntry *' (or there is no acceptable conversion) c:\users\cross_000\documents\visual studio 2013\projects\objectorientedmethodsasignment1\mapadt\mapadt.h 14
So I thought I would write my own Assignment operator override. I've done this in the MapEntry class definition but the compiler doesn't seem to recognize it when I try to initialize the array in the constructor on MapADT - below.
Any help would be greatly appreciated.
#pragma once
template <class Tk, class Tc>
class MapEntry
{
private:
Tk key;
Tc contents;
bool isPopulated;
public:
MapEntry() {
}
MapEntry(Tk keyInput, Tc contentsInput) {
key = keyInput;
contents = contentsInput;
isPopulated = true;
}
MapEntry(Tk keyInput, Tc contentsInput, bool isPopulatedInput) {
key = keyInput;
contents = contentsInput;
isPopulated = isPopulatedInput;
}
~MapEntry() {
//TODO
}
Tk getKey() {
return key;
}
void setKey(Tk keyInput) {
key = keyInput;
}
Tc getContents() {
return contents;
}
void setContents(Tc contentsInput) {
contents = contentsInput;
}
bool getIsPopulated() {
return isPopulated;
}
void setIsPopulated(bool isPopulatedInput) {
isPopulated = isPopulatedInput;
}
MapEntry<Tk, Tc>& operator=(const MapEntry<Tk, Tc> & lst)
{
clear();
copy(lst);
return *this;
}
};
MapADT.h
#pragma once
#include "MapEntry.h"
template <class Tk, class Tc>
class MapADT
{
private:
int mapSize = 1000;
MapEntry<Tk, Tc> *map;
public:
MapADT() {
map = new MapEntry<Tk, Tc>[mapSize];
for (int i = 0; i < mapSize; i++) {
map[i] = new MapEntry<Tk, Tc>(NULL, NULL, false);
}
}
}
There's more to the MapADT class but I don't think it's relevant. If you need to see the whole thing I can add it.
map[i] is not an pointer to MapEntry.
Not sure if you want
map[i] = MapEntry<Tk, Tc>(NULL, NULL, false);
or
MapEntry<Tk, Tc>** map;
MapADT() {
map = new MapEntry<Tk, Tc>*[mapSize];
for (int i = 0; i < mapSize; i++) {
map[i] = new MapEntry<Tk, Tc>(NULL, NULL, false);
}
}
to solve your issue.
In this line
map = new MapEntry<Tk, Tc>[mapSize];
you allocate an array of MapEntry<Tk, Tc>, and default constructors are called for all of them. There's no need in subsequent for loop at all, you should just write proper initialization in MapEntry::MapEntry(), which is currently empty.