I am literally freaking out on the following :
template <class T> // int, float, double etc..
class Graph {
public:
// Documentation, it has to be between [0..100]
Graph(int size = 10, int density = 10, T range = 0):
m_size(size),
m_density(density),
m_range(range) {
generate();
}
~Graph() {
for (int i = 0; i < m_size; i++)
delete[] m_graph[i];
delete[] m_graph;
}
[..]
static Graph<T>* custom(T** cgraph, int size, T range) {
Graph<T> *graph = new Graph<T>(size, 10, range);
for (int i = 0; i < size; i++)
delete[] graph->m_graph[i];
delete[] graph->m_graph;
graph->m_graph = cgraph;
}
private:
T** m_graph;
[ .. ]
};
int nodes[4][4] = {
{ 6, 5, 2, 5 },
{ 5, 6, 3, 3 },
{ 1, 3, 6, 1 },
{ 5, 3, 1, 6 }
};
int main() {
Graph<int> *graph = Graph<int>::custom(nodes, 4, 5);
}
What is it poorly failing to compile reporting the following errors ?
g++ graph.cpp -o test_graph
graph.cpp: In function ‘int main()’:
graph.cpp:191:55: error: no matching function for call to ‘Graph<int>::custom(int [4][4], int, int)’
Graph<int> *graph = Graph<int>::custom(nodes, 4, 5);
^
graph.cpp:60:20: note: candidate: static Graph<T>* Graph<T>::custom(T**, int, T) [with T = int]
static Graph<T>* custom(T** cgraph, int size, T range) {
^
graph.cpp:60:20: note: no known conversion for argument 1 from ‘int [4][4]’ to ‘int**’
It looks so right to me, what's wrong ?
You need to make nodes by an array of pointers to int.
int nodes_v[4][4] = {
{ 6, 5, 2, 5 },
{ 5, 6, 3, 3 },
{ 1, 3, 6, 1 },
{ 5, 3, 1, 6 }
};
int *nodes[4] = { nodes_v[0], nodes_v[1], nodes_v[2], nodes_v[3] };
You also need to add an additional member to the Graph variable to mark that it is a custom graph, and if set, the destructor should not delete the memory.
Best to give Graph a private constructor which passes in the custom flag and doesn't bother allocating the memory if set.
Graph(int size, int density, T range, bool custom):
m_size(size),
m_density(density),
m_range(range),
m_custom {
}
Graph(int size = 10, int density = 10, T range = 0):
Graph(size, density, range, false) {
generate();
}
static Graph<T>* custom(T** cgraph, int size, T range) {
Graph<T> *graph = new Graph<T>(size, 10, range, true);
graph->m_graph = cgraph;
}
Finally, you need to handle copy constructor and assignment operator (start by just deleting them).
Related
Im trying myself on clang-format and went ofter the documentation over and over again but I cant find this specific switch. This is what clang-format does
int foo(int, std::vector<int>) {
return 0;
}
int bar(std::vector<int>) {
return 1;
}
int a = foo(0, {
1,
2,
3,
4,
});
int b = bar({
0,
1,
2,
3,
});
Id like to have it like this
int foo(int, std::vector<int>) {
return 0;
}
int bar(std::vector<int>) {
return 1;
}
int a = foo(0, {
1,
2,
3,
4,
});
int b = bar({
0,
1,
2,
3,
});
Here is my .clang-format so far
https://pastebin.com/ikGE5e7s
I read about the vector/list/map types contained in the stardard template library of C++ and I couldn't find one that behaved as such:
myMap::autofillingmap m;
m[0] = 2; // m[] = [2]
m[1] = 3; // m[] = [2, 3]
m[4] = 5; // m[] = [2, 3, 0, 0, 5]
m[10] = 1 // m[] = [2, 3, 0, 0, 5, 0, 0, 0, 0, 0, 1]
Is there any cpp lib that emulates this behavior?
(beforehand observation: Yes, I do know this is not optimal methodology to work data structures out. Thanks)
I have wrote myMap struct which use a std::vector<int> to store values, myMap I also have tried a basic Insert() method that interpret your example to assign values.
struct myMap {
vector<int> _data;
size_t _capacity;
myMap(size_t capacity);
const myMap& operator=(const myMap&);
int operator [] (int index);
void Insert(int idx, int value);
};
myMap::myMap(size_t capacity) : _capacity(capacity) {
_data.resize(capacity);
}
const myMap& myMap::operator=(const myMap& rhs){
_data = rhs._data;;
return *this;
}
int myMap::operator[](int idx) {
return _data[idx];
}
void myMap::Insert(int idx, int value) {
if (idx >= _data.size())
_data.resize(idx+1);
_data[idx] = value;
}
demo
Usually array could be initialized like this:
int ooo[3][3] =
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
I need to hide it into the custom structure like this:
template <typename T, size_t dim1, size_t dim2>
struct MyStruct
{
private:
T m_data[dim1][dim2];
};
How to pass the initialization to the array like in the foolowing case?
MyStruct<int, 3, 3> s =
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
It would work if you can make the member public, and add a set of braces. This is aggregate initialisation:
MyStruct<int, 3, 3> s =
{{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 },
}};
I need to hide it into the custom structure ...
If you need the member to be private, you cannot rely on aggregate initialisation since the class won't be an aggregate. You can still achieve similar syntax if you define a custom constructor. Here is an example using std::initializer_list. This one doesn't require the extra braces.
Edit: This isn't as good as the array reference example in the other answer.
MyStruct(std::initializer_list<std::initializer_list<T>> ll)
{
auto row_in = ll.begin();
for (auto& row : m_data)
{
auto col_in = (row_in++)->begin();
for (auto& i : row)
{
i = *col_in++;
}
}
}
You can add a constructor to your class that takes a 2D array argument, and copies it into the array member:
template <typename T, size_t dim1, size_t dim2>
struct MyStruct
{
private:
T m_data[dim1][dim2];
public:
MyStruct(T const (&a)[dim1][dim2]) {
for (int i = 0; i < dim1; ++i)
for (int j = 0; j < dim2; ++j)
m_data[i][j] = a[i][j];
}
};
You also need to add an extra pair of braces at the call site.
Here's a demo.
Edit: Added constructors and add function
Consider the following three blocks:
//ONE
template<typename T>
class List1 {
private:
uint32_t capacity;
uint32_t used;
T* data;
void checkGrow() {
if (used < capacity)
return;
T* old = data;
capacity*=2;
data = (T*)new char[sizeof(T) * capacity];
memcpy(data, old, sizeof(T)*used);
delete (void*)old;
}
public:
List1() : capacity(1), used(0), data((T*)new char [sizeof(T)]) {}
List1(uint32_t initialSize) :
capacity(initialSize), used(0), data((T*)new char[sizeof(T)]) {}
List1(const List1& orig) :
capacity(orig.capacity), used(orig.used), data((T*)new char[used * sizeof(T)]) {
memcpy(data, orig.data, used * sizeof(T));
}
uint32_t serializeSize() const { return sizeof(used) + used*sizeof(T); }
char* read(char* p) {
used = *(uint32_t*)p;
p += sizeof(uint32_t);
data = (T*)new char[used*sizeof(T)];
memcpy(p, data, used * sizeof(T));
return p + used*sizeof(T);
}
char* write(char* p) {
*(uint32_t*)p = used;
p += sizeof(uint32_t);
memcpy(p, data, used * sizeof(T));
return p + used * sizeof(T);
}
~List1() { delete [] data; }
void add(const T& v) {
checkGrow();
data[used++] = v;
}
uint32_t getUsed() const{
return used;
}
uint32_t getCapacity() const{
return capacity;
}
//const T& operator [](int i) const { return data[i]; }
//T& operator [](int i) { return data[i]; }
T getData (int i) const{
return data[i];
}
uint32_t size() const { return used * sizeof(T); }
};
//TWO
List1<uint32_t> temp=in.readList<uint32_t>(); // <List1<uint32_t>>();
//BREAKPOINT HERE
for(uint i=0;i<15;i++){
//cout<<temp[i]<<endl;
cout<<temp.getData(i)<<endl;
}
//THREE
template<typename T>
T _read() {
T temp = *(T*)p;
p += sizeof(T);
availRead -= sizeof(T);
return temp;
}
template<typename T>
T read(){
//cout << (uint64_t)p << endl;
checkAvailableRead(sizeof(T));
return _read<T>();
}
template<typename T>
List1<T> readList(){
uint32_t len = read<uint32_t>();
List1<T> temp(len);
for (uint i = 0 ; i < len; i++){
T val =read<T>();
temp.add(val);
//HERE: For some reason code does not work without this print statement
//cout<<temp.getData(i)<<endl;
}
return temp;
}
Basically the issue is that the value of data changes from after returning from getData as shown below.
gdb) p/u *temp.data#15
$1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
(gdb) p/u *temp.data#15
$2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
(gdb) p/u *data#15
$3 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
[New Thread 8444.0xad8]
(gdb) p/u *data#15
$4 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
[New Thread 8444.0x214c]
(gdb) p/u *temp.data#15
$5 = {0, 1, 2, 3, 4, 5, 83, 0, 2150008464, 1, 3742232646, 0, 168272, 6, 0}
For some reason adding a print statement to readList fixes the issue, but that isn't a reasonable solution. I've tried a few different variations on the code but none of them worked.
I'm not sure what the issue is or how to even begin debugging as the problem occurs between the return statement and the next iteration of the loop (there's nothing to step into there).
Any advice would be greatly appreciated.
List1(const List1& orig) :
capacity(orig.capacity), used(orig.used), data((T*)new char[used * sizeof(T)]) {
memcpy(data, orig.data, used * sizeof(T));
}
For List1 to work correctly, there must never be a List1 whose capacity is greater than the actual allocated size. However, this creates a new List1 that violates this invariant if orig has a capacity greater than its used.
You probably meant capacity(orig.used).
Same issue here:
List1(uint32_t initialSize) :
capacity(initialSize), used(0), data((T*)new char[sizeof(T)]) {}
If you set capacity to initialSize, you can't allocate space for just 1 T.
This is also broken delete (void*)old;. What you allocate with new[], you must free with delete[].
Note that List1 can only be used to hold POD types (plain old data) that don't have constructors or destructors. If you're trying to use List1 to hold anything more complex, you're way off base with your design.
I have designed a matrix class. Now I would like to initialize via list
Matrix3D m2{{1,2,3},{4,5,6},{7,8,9}};
instead of
Matrix3D m1(1,2,3,4,5,6,7,8,9);
I have added a static assert to force the size of the matrix which does not work.
How should I modify the constructor?
#include <iostream>
using namespace std;
class Matrix3D
{
int a11;
int a12;
int a13;
int a21;
int a22;
int a23;
int a31;
int a32;
int a33;
public:
Matrix3D(
int a11,
int a12,
int a13,
int a21,
int a22,
int a23,
int a31,
int a32,
int a33):
a11(a11),
a12(a12),
a13(a13),
a21(a21),
a22(a22),
a23(a23),
a31(a31),
a32(a32),
a33(a33)
{
}
Matrix3D(std::initializer_list<std::initializer_list<double>> listlist);
};
Matrix3D::Matrix3D(std::initializer_list<std::initializer_list<double>> listlist)
{
constexpr int rows = (int)(listlist.begin()).size();
constexpr int cols = (int)listlist.size();
static_assert(rows == 3, "");
static_assert(cols == 3, "");
a11=(listlist.begin()+0)[0];
a12=(listlist.begin()+0)[1];
a13=(listlist.begin()+0)[2];
a21=(listlist.begin()+1)[0];
a22=(listlist.begin()+1)[1];
a23=(listlist.begin()+1)[2];
a31=(listlist.begin()+2)[0];
a32=(listlist.begin()+2)[1];
a33=(listlist.begin()+2)[2];
}
int main() {
Matrix3D m1(1,2,3,4,5,6,7,8,9);
Matrix3D m2{{1,2,3},{4,5,6},{7,8,9}};
return 0;
}
I have added a static assert to force the size of the matrix which does not work.
Unfortunately for your situation std::initializer_list<Elem> is designed for a variable number of elements, which is why you cannot statically say anything about its size in the general case. The fact that its size member is constexpr is a red herring:
constexpr std::initializer_list<int> constant_expr = { 0, 2, 4, 6 };
// this is what a constexpr size member makes possible
static_assert( constant_expr.size() == 4 );
std::initializer_list<int> non_constant_expr = { 1, 3, 5 };
// this can't work
//static_assert( non_constant_expr.size() == 3 );
Function parameters are not constant expressions.
Instead, you would be better served by a type with a statically known number of elements. Array references can be suited to your needs:
class Matrix3D {
using index_type = int;
static constexpr index_type cols = 3;
using row_arg_type = int[cols];
public:
Matrix3D(row_arg_type const& row0, row_arg_type const& row1, row_arg_type const& row2);
// rest of class omitted
};
// number of rows and row width are statically enforced
Matrix3D m = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
Coliru demo