Constant container (map) - eliminate heap allocation - dictionary

If I create a static const std::map, it will allocate memory on heap. Following code throws bad_alloc:
#include <iostream>
#include <map>
class A {
public:
static const std::map<int, int> a;
};
const std::map<int, int> A::a = { { 1, 3} , { 2, 5} };
void* operator new ( std::size_t count )
{
throw std::bad_alloc();
}
int
main (void)
{
for(auto &ai: A::a) {
std::cout << ai.first << " " << ai.second << "\n";
}
return 0;
}
Is it possible to create this constant map somehow without having memory allocation?

As Igor Tandetnik suggested, a custom allocator would do the trick. The following is a quick'n'dirty example of a simple linear allocator, which returns memory slots from a static buffer:
#include <iostream>
#include <map>
#include <cassert>
template <typename T>
class LinearAllocator {
static constexpr size_t _maxAlloc = 1<<20;
using Buffer = std::array<T, _maxAlloc>;
using FreeList = std::array<bool, _maxAlloc>;
static Buffer _buffer;
static FreeList _allocated;
public:
typedef T* pointer;
typedef T value_type;
template<typename U>
struct rebind { typedef LinearAllocator<U> other; };
pointer allocate(size_t /*n*/, const void *hint=0) {
for(size_t i = 0; i < _maxAlloc; ++i) {
if(!_allocated[i]) {
_allocated[i] = true;
return &_buffer[i];
}
}
throw std::bad_alloc();
}
void deallocate(pointer p, size_t /*n*/) {
assert(p >= &_buffer[0] && p < &_buffer[_maxAlloc]);
_allocated[p-&_buffer[0]] = false;
}
LinearAllocator() throw() { }
LinearAllocator(const LinearAllocator &a) throw() { }
template <class U>
LinearAllocator(const LinearAllocator<U> &a) throw() { }
~LinearAllocator() throw() { }
};
template <typename T>
typename LinearAllocator<T>::Buffer LinearAllocator<T>::_buffer;
template <typename T>
typename LinearAllocator<T>::FreeList LinearAllocator<T>::_allocated;
using MyMap = std::map<int, int, std::less<int>,
LinearAllocator<std::pair<int,int> > >;
// make sure we notice if new gets called
void* operator new(size_t size) {
std::cout << "new called" << std::endl;
}
int main() {
MyMap m;
m[0] = 1; m[1] = 3; m[2] = 8;
for(auto & p : m)
std::cout << p.first << ": " << p.second << std::endl;
return 0;
}
Output:
0: 1
1: 3
2: 8
Note that this allocator will only handle requests for single slots at a time. I'm sure you will figure out how to extend it according to your requirements.

Related

Getting two errors E0289 and C2440 pointing at initialization of vector

I am getting these two errors when initializing vc below.
#include <iostream>
#include <complex>
#include <math>
#include <vector>
#include <limits>
#include <list>
#include <string>
class Vector {
private:
double* elem; // elem points to an array of sz doubles
int sz;
public:
Vector(int s) :elem{ new double [s] }, sz{ s } // constructor: acquire resources
{
for (int i = 0; i != s; ++i) elem[i] = 0; // initialize elements
~Vector() { delete[] elem; } // destructor: release resources
double& operator[](int i);
int size() const;
void push_back(double);
};
double& Vector::operator[](int i)
{
// TODO: insert return statement here
// added below since the funtion needs to return a double and
return elem[i];
}
int Vector::size() const
{
return sz;
}
void Vector::push_back(double)
{
}
class Container {
public:
virtual double& operator[](int) = 0; // pure virtual function
virtual int size() const = 0; // const member function (§3.2.1.1)
virtual ~Container() {} // destructor (§3.2.1.2)
};
// use function uses Container interface.
void use(Container& c)
{
const int sz = c.size();
for (int i=0; i!=sz; ++i)
cout << c[i] << '\n';
}
class Vector_container : public Container { // List_container implements Container
Vector v;
public:
Vector_container(int s) : v(s) {} // Vector of s elements
void ˜Vector_container() {}
double& operator[](int i) { return v[i]; }
int size() const { return v.size(); }
};
void main()
{
Vector_container vc = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
use(vc)
}
I receive both errors pointing at this line Vector_container vc = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }
Error E0289 is - no instance of constructor "Vector_container::Vector_container" matches the argument list
Error C2440 'initializing': cannot convert from 'initializer list' to 'Vector_container'
I was able to solve the issue by modifying the Vector_container and initializing using Initializer-list constructor below:
class Vector_container : public Container {
std::list<double> ld;
public:
Vector_container() { }
Vector_container(initializer_list<double> il) : ld{ il } {}
~Vector_container() {}
double& operator[](int i);
int size() const { return ld.size(); }
};
double& Vector_container::operator[](int i)
{
for (auto& x : ld) {
if (i == 0) return x;
--i;
}
}

I am trying to print Reverse of a Sequence of Numbers using Stack. Stack is implemented using Vector. But I am getting Segmentation Fault

Can you please help me find the error in printing the reverse of sequence using stacks implemented by vector?
I am getting a Segmenattion fault
#include <iostream>
#include<vector>
using namespace std;
class stack{
public :
int top;
vector<int> data;
bool isempty(){return top == -1;}
void push(int x){data[++top] = x;}
void pop(){--top;}
int topper(){return data[top];}
};
int main()
{
stack s;
int n;
s.top = -1;
cout << "enter the number of integers" << endl;
cin >> n;
for(int i =0; i < n; i ++){
s.push(i);
}
while(!s.isempty()){
cout << s.topper();
s.pop();
}
return 0;
}
This problem occurs, because a vector has size = 0 by default.
You can either resize the vector, before you add values into it like so:
#include <iostream>
#include<vector>
using namespace std;
class stack {
public:
int top;
vector<int> data;
bool isempty() { return top == -1; }
void push(int x) { data.resize(++top+1); data[top] = x; }
void pop() { --top; }
int topper() { return data[top]; }
};
int main()
{
stack s;
int n;
s.top = -1;
cout << "enter the number of integers" << endl;
cin >> n;
for (int i = 0; i < n; i++) {
s.push(i);
}
while (!s.isempty()) {
cout << s.topper();
s.pop();
}
return 0;
}
Or you can use the built-in functionality for vectors like that, which I think is the far better solution:
#include <iostream>
#include<vector>
using namespace std;
class stack {
public:
vector<int> data;
bool isempty() { return data.size() == 0; }
void push(int x) { data.push_back(x); }
void pop() { data.pop_back(); }
int topper() { return data.back(); }
};
int main()
{
stack s = stack();
int n;
cout << "enter the number of integers" << endl;
cin >> n;
for (int i = 0; i < n; i++) {
s.push(i);
}
while (!s.isempty()) {
cout << s.topper();
s.pop();
}
return 0;
}

Segmentation fault inside range

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue> // std::priority_queue
using std::vector;
using std::cin;
using std::cout;
struct fj{
int indexI=0;
int freeT=0;
};
struct DereferenceCompareNode : public std::binary_function<fj, fj, bool>
{
bool operator()(const fj lhs, const fj rhs) const
{
return lhs.freeT > rhs.freeT;
}
};
class JobQueue {
private:
int num_workers_;
vector<int> jobs_;
vector<int> assigned_workers_;
vector<long long> start_times_;
void WriteResponse() const {
for (int i = 0; i < jobs_.size(); ++i) {
cout << assigned_workers_[i] << " " << start_times_[i] << "\n";
}
}
void ReadData() {
int m;
cin >> num_workers_ >> m;
jobs_.resize(m);
std::cout<<"Read fault"<<"\n";
for(int i = 0; i < m; i++)
cin >> jobs_[i];
std::cout<<"Read fault ends"<<"\n";
}
void AssignJobs() {
// TODO: replace this code with a faster algorithm.
std::cout<<"Fault point 1"<<"\n";
assigned_workers_.resize(jobs_.size());
start_times_.resize(jobs_.size());
vector<long long> next_free_time(num_workers_, 0);
std::priority_queue<int, vector<int>, std::greater<int> > thread;
std::priority_queue<fj, vector<fj>, DereferenceCompareNode > freeJob;
/*
for (int i = 0; i < jobs_.size(); ++i) {
int duration = jobs_[i];
int next_worker = 0;
for (int j = 0; j < num_workers_; ++j) {
if (next_free_time[j] < next_free_time[next_worker])
next_worker = j;
}
assigned_workers_[i] = next_worker;
start_times_[i] = next_free_time[next_worker];
next_free_time[next_worker] += duration;
}
*/
std::cout<<"dump point 2"<<"\n";
for(int i=0;i<num_workers_;i++){
thread.push(i);
}
std::cout<<"dump point 1"<<"\n";
int counter = 0;
while(jobs_.size()!=0){
std::cout<<"jobs_.size:"<<jobs_.size()<<"\n";
std::cout<<"freeJob.size:"<<freeJob.size()<<"\n";
//check logic
do{
if(freeJob.top().freeT == counter){
std::cout<<"freeJob.top().freeT:"<<freeJob.top().freeT<<"\n";
std::cout<<"counter:"<<counter<<"\n";
thread.push(freeJob.top().indexI);
freeJob.pop();
}else{
break;
}
}
while(freeJob.size()!=0);
std::cout<<"Thread:"<<thread.size()<<"\n";
while(thread.size()!=0){
if(jobs_.size()!=0){
fj currA;
currA.indexI = thread.top();
currA.freeT = jobs_.at(0)+counter;
std::cout<<"currA.indexI:"<<currA.indexI<<"\n";
std::cout<<"currA.freeT:"<<currA.freeT<<"\n";
thread.pop();
jobs_.erase(jobs_.begin());
assigned_workers_.push_back(currA.indexI);
start_times_.push_back(currA.freeT);
}else{
break;
}
}
counter++;
}
}
public:
void Solve() {
ReadData();
AssignJobs();
WriteResponse();
}
};
int main() {
std::ios_base::sync_with_stdio(false);
JobQueue job_queue;
job_queue.Solve();
return 0;
}
I am getting segmentation fault in function ReadData while taking inputs for vector jobs.
I am getting fault even when I am inside bounds of defined size.
Everything was fine when have not written AssignJob function.
Am I doing something wrong with some bounds or taking illegal inputs format or messing with some other stuff?
Am I doing something wrong
Yes, you are: freeJob starts out empty, so this is undefined behavior:
if(freeJob.top().freeT == counter){
In fact, you never push anything into freeJob, you only pop() things from it.

How to attach to existing shared memory from Qt?

I have created a shared memory segment with the help of a binary in C and written some data into it. Now I want read that data from Qt. How to attach to existing shared memory from Qt?
QSharedMemory isn't really meant to interoperate with anything else. On Unix, it is implemented via SYSV shared memory, but it passes Qt-specific arguments to ftok:
::ftok(filename.constData(), qHash(filename, proj_id));
You could emulate this behavior in your C code, but I don't think it's necessary.
Instead of opening a shared memory segment, simply map a file to memory, and access it from multiple processes. On Qt, QFile::map does what you need.
The example below shows both techniques: using SYSV shared memory and using memory-mapped files:
// https://github.com/KubaO/stackoverflown/tree/master/questions/sharedmem-interop-39573295
#include <QtCore>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <stdexcept>
#include <string>
First, let's have a shared data structure.
struct Data {
int a = 1;
bool b = true;
char c = 'S';
bool operator==(const Data & o) const { return o.a == a && o.b == b && o.c == c; }
static void compare(const void * a, const void * b) {
auto data1 = reinterpret_cast<const Data*>(a);
auto data2 = reinterpret_cast<const Data*>(b);
Q_ASSERT(*data1 == *data2);
}
};
We definitely want error checking, so let's add some helpers that make that easier:
void check(bool ok, const char * msg, const char * detail) {
if (ok) return;
std::string str{msg};
str.append(": ");
str.append(detail);
throw std::runtime_error{str};
}
void check(int f, const char * msg) { check(f != -1, msg, strerror(errno)); }
void check(void * f, const char * msg) { check(f != MAP_FAILED, msg, strerror(errno)); }
void check(bool rc, const QSharedMemory & shm, const char * msg) { check(rc, msg, shm.errorString().toLocal8Bit()); }
void check(bool rc, const QFile & file, const char * msg) { check(rc, msg, file.errorString().toLocal8Bit()); }
And we need RAII wrappers for C APIs:
struct noncopyable { Q_DISABLE_COPY(noncopyable) noncopyable() {} };
struct ShmId : noncopyable {
int id;
ShmId(int id) : id{id} {}
~ShmId() { if (id != -1) shmctl(id, IPC_RMID, NULL); }
};
struct ShmPtr : noncopyable {
void * ptr;
ShmPtr(void * ptr) : ptr{ptr} {}
~ShmPtr() { if (ptr != (void*)-1) shmdt(ptr); }
};
struct Handle : noncopyable {
int fd;
Handle(int fd) : fd{fd} {}
~Handle() { if (fd != -1) close(fd); }
};
Here's how to interoperates SYSV shared memory sections between C and Qt. Unfortunately, unless you reimplement qHash in C, it's not possible:
void ipc_shm_test() {
QTemporaryFile shmFile;
check(shmFile.open(), shmFile, "shmFile.open");
// SYSV SHM
auto nativeKey = QFile::encodeName(shmFile.fileName());
auto key = ftok(nativeKey.constData(), qHash(nativeKey, 'Q'));
check(key, "ftok");
ShmId id{shmget(key, sizeof(Data), IPC_CREAT | 0600)};
check(id.id, "shmget");
ShmPtr ptr1{shmat(id.id, NULL, 0)};
check(ptr1.ptr, "shmat");
new (ptr1.ptr) Data;
// Qt
QSharedMemory shm;
shm.setNativeKey(shmFile.fileName());
check(shm.attach(QSharedMemory::ReadOnly), shm, "shm.attach");
auto ptr2 = shm.constData();
Data::compare(ptr1.ptr, ptr2);
}
Here's how to interoperate memory-mapped files:
void mmap_test() {
QTemporaryFile shmFile;
check(shmFile.open(), "shmFile.open");
shmFile.write({sizeof(Data), 0});
check(true, shmFile, "shmFile.write");
check(shmFile.flush(), shmFile, "shmFile.flush");
// SYSV MMAP
Handle fd{open(QFile::encodeName(shmFile.fileName()), O_RDWR)};
check(fd.fd, "open");
auto ptr1 = mmap(NULL, sizeof(Data), PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd.fd, 0);
check(ptr1, "mmap");
new (ptr1) Data;
// Qt
auto ptr2 = shmFile.map(0, sizeof(Data));
Data::compare(ptr1, ptr2);
}
And finally, the test harness:
int main() {
try {
ipc_shm_test();
mmap_test();
}
catch (const std::runtime_error & e) {
qWarning() << e.what();
return 1;
}
return 0;
}

Pass QScopedPointer to function

How can I pass a QScopedPointer object to another function like that:
bool addChild(QScopedPointer<TreeNodeInterface> content){
TreeNode* node = new TreeNode(content);
}
TreeNode:
TreeNode::TreeNode(QScopedPointer<TreeNodeInterface> content)
{
mContent.reset(content.take());
}
I get:
error: 'QScopedPointer::QScopedPointer(const QScopedPointer&) [with T = TreeNodeInterface; Cleanup = QScopedPointerDeleter]' is private
How can I solve it? Thanks!
You can do it by accepting a reference to the pointer - that way you can swap the null local pointer with the one that was passed to you:
#include <QScopedPointer>
#include <QDebug>
class T {
Q_DISABLE_COPY(T)
public:
T() { qDebug() << "Constructed" << this; }
~T() { qDebug() << "Destructed" << this; }
void act() { qDebug() << "Acting on" << this; }
};
void foo(QScopedPointer<T> & p)
{
using std::swap;
QScopedPointer<T> local;
swap(local, p);
local->act();
}
int main()
{
QScopedPointer<T> p(new T);
foo(p);
qDebug() << "foo has returned";
return 0;
}
Output:
Constructed 0x7ff5e9c00220
Acting on 0x7ff5e9c00220
Destructed 0x7ff5e9c00220
foo has returned

Resources