I am currently working on building an ABM model using C++.
I have classes that have the need to interact with each other, because e.g. class B needs to examine values in class A and return some evaluation on it, which then class C might want to read. Classes need not to change other classes values, only to read from them.
Class B in my current implementation has a po
inter to a vector containing all members of Class A. The pointer is there for two order of reason: it makes easier to initialize the vector, and the vector is left in the scope of main so that I can access and loop over it, calling the members of class A for each agent.
My MCVE:
#include <iostream>
#include <vector>
using namespace std;
class A; // Forward declaration
class B{
int id,
some_value;
vector<A> * A_vec;
public:
// Overloaded constructor
B(int ID, vector<A> & PTR)
{
A_vec = & PTR;
id = ID;
some_value = 0;
};
// Copy Constructor
B( const B& that ):
id(that.id),
some_value(that.some_value)
{
// Pointer ??
};
// Non-default destructor -> uncomment leads to seg_fault
/*
~B(){ delete [] A_vec;};
*/
// Assignment operator
B& operator=(const B& that)
{
id = that.id;
some_value = that.some_value;
// Pointer ??
return *this;
};
//Methods to update different variables go here ..
void do_stuff();
};
class A{
B & class2_ref;
vector<double> o;
public:
int stuff;
// Overloaded constructor
A(int STUFF, B & REF, vector<double> O):
class2_ref(REF),
o(O)
{
stuff = STUFF;
};
// Methods to update different variables go here ..
};
void B::do_stuff()
{
int L = A_vec->size();
for(int l = 0; l<L; l++) some_value += (*A_vec)[l].stuff; // Perform some operation
};
int main(){
int I = 5; // Number of objects of A
vector<double> O(12,2); // Some numbers in here
B b(0,A_vec);
for(int i = 0; i< I; i++)
{
A a(i,b,O);
A_vec.push_back(a);
}
b.do_stuff();
cout<< "Debugging MCVE" << endl;
return 0;
}
My question then is:
Should I implement the destructor/copy constructor/assignment operator in class B? What about class A ? If so, can you please point me to the correct syntax(for the destructor the one above in comments leads to seg fault).
My understanding is that this might be one of the case in which I am happy with a "shallow" destruction of the pointer, because both class B and vector<A> will go out of scope at the return statement. class B owns the pointer, which gets destructed when it is due, and the same for vector.
But then, what about the other member from the rule of three?
There is only one object of class B planned, but I might (small chance) want to generalize later on.
if a class have a pointer type, you should implement a destructor, and i would suggest implementing a copy and an assignment operator as well, else you will be dealing with the same object from 2 different places, which could cause you some errors, for example -
void someFunction(B &b)
{
B a = b;
}
B b(0,A_vec);
someFunction(b); //After finishing someFunction, it will try to delete the vector from a , but it is the same vector you used in b.
b.do_stuff(); // Would cause a seg error
And for the destructor syntax, just delete the vector, not its content, it will use the vector default destrctor on the content:
delete A_vec
just make sure you dont use it if its not initialized, i would suggest just building a empty vector on each ctor of the class, that way you wont get a seg fault and you can use delete.
Related
I am trying to implement bigint class in c++, it's not completed yet, i have encountered some errors that i am unable understand.
I have erased all other functions (as they are unnecessary in this case)
and karatsuba is not yet completed (but that should't pose a problem in this case).
In the multiply function (overloaded * ) my compiler gives an error:
passing 'const BigInt' as 'this' argument discards qualifiers [-fpermissive]
at line
ans.a = karatsuba(n,m);
I understand that this would occur when i am trying to change a constant object or object passed to a constant function, in my case i am merely creating a new vector and passing it to karatsuba function.
Removing const from overloded * gets rid of this error.
So,does this mean that a constant function can't change anything at all? (including local variables?)
class BigInt {
typedef long long int ll;
typedef vector<int> vi;
#define p10 1000000000;
#define range 9
vi a;
bool sign;
public:
BigInt operator * (const BigInt &num) const
{
vi n(a.begin(),a.end()),m(num.a.begin(),num.a.end());
BigInt ans;
ans.sign = !(sign ^ num.sign);
while(n.size()<m.size()) n.push_back(0);
while(n.size()>m.size()) m.push_back(0);
ans.a = karatsuba(n,m);
return ans;
}
vi karatsuba(vi a,vi b)
{
int n = a.size();
if(n <= 16)
{
// some code
}
// some code
return a;
}
};
Ok so after googling a bit more, i realized that this pointer is implicitly passed to the oveloaded * and then on to karatsuba (as it is a member function of the class), and as karatsuba is not a constant function, there is no guarantee that it won't change the object contents, hence this error is triggered.
One solution is to declare karatsuba as static, as static member functions don't receive this pointer (they can even be called with out a class object simply using :: operator) , read more about them from here Static data members and member functions.
All that is needed to be changed is :-
static vi karatsuba(vi a,vi b)
{
int n = a.size();
if(n <= 16)
{
// some code
}
// some code
return a;
}
I have a class with a rand data member i. This class (child) is a member of class parent, which also has a data member i. I would like to constrain the value of i in the child class to be the same as the value of i in the parent class. I want to do something like:
c.randomize with {i==this.i;};
but the this.i doesn't seem to refer to the i data member of the parent class. (Why?)
I can do this:
function void f;
int dummy = i;
c.randomize with {i==dummy;};
endfunction
or this:
function void f;
c.randomize with {i==m.blk.p.i;}; // yuck!
endfunction
but wonder if there is a better (built-in, non-hacky) way of distinguishing between the two is.
MCVE:
class child;
rand int i;
endclass
class parent;
child c = new;
int i=1;
function void f;
c.randomize with {i==this.i;};
endfunction
endclass
module m;
initial begin : blk
parent p = new;
p.f;
$display("%p", p);
end
endmodule
https://www.edaplayground.com/x/2_8P
You want {i==local::i}. See section 18.7.1 of the 1800-2017 LRM
The reason this.i does not do what you expect is the combination of these two rules:
all class methods, including the built-in randomize method, have a built-in this argument. So c.method(args) is really method(args, c) and this becomes a variable local to the method set to the value of c
Identifiers within the with clause try to bind into the scope being randomized first before searching locally at the point where calling randomize().
So i and this.i refer to the same class variable just as if you wrote
class A;
bit i;
function void method;
i = 1;
this.i = 2;
endfunction
endclass
The examples for placement new often use unsigned char arrays as the underlying storage. The steps can be:
create the unsigned char array with new
create an object in this storage with placement new
use object
destroy object
call delte for the unsigned char array to free the array
Point 5. seems only to work if we use a type for the underlying storage with a trivial destructor. Otherwise, we would call the destructor of the underlying storage type but with no object existing there. Technically, we are destructing a bunch of unsigned chars which are not present and we are lucky that the desturctor of the unsigned char type is trivial and so no-op.
What about the following code:
struct A{ /* some members... */ };
struct B{ /* some members... B shall be same size as A */ };
int main()
{
auto ptr_to_a = new A; // A object lives # ptr_to_a
ptr_to_a->~A(); // A object destroyed. no object living # ptr_to_a, but storage is preserved
new (ptr_to_a) B; // B object living # ptr_to_a.
std::launder(reinterpret_cast<b*>(ptr_to_a))->/*...*/; // use B. for this purpose we need std::launder in C++17 or we would store the pointer returned by the placement new and use it without std::launder
std::launder(reinterpret_cast<b*>(ptr_to_a))->~B(); // B object destroyed. no object living # ptr_to_a, but storage is preserved
// at this point there is no object living # ptr_to_a, but we need to hand back the occupied storage.
// a)
delete ptr_to_a; // undefined behavior because no object is sitting # ptr_to_a
// b)
new (ptr_to_a) A; // create an object again to make behavior defined. but this seems odd.
delete ptr_to_a;
// c)
// some method to just free the memory somehow without invoking destructors?
return 0;
}
On https://en.cppreference.com/w/cpp/language/lifetime is written:
As a special case, objects can be created in arrays of unsigned char or std::byte (in which case it is said that the array provides storage for the object) if... .
Does this imply, that its only allowed to use placement new on unsigned char and byte arrays and because they have a trivial destructor my code sample is obsolete?
Otherwise, how about my codesample? Is option b) the only valid solution?
Edit: second examlpe:
struct A{ /* some members... */ };
struct alignas(alignof(A)) B{ /* some members... */ };
int main()
{
static_assert(sizeof(A) == sizeof(B));
A a;
a.~A();
auto b_ptr = new (&a) B;
b_ptr->~B();
return 0;
// undefined behavior because a's destructor gets called but no A object is "alive" (assuming non trivial destructor)
// to make it work, we need to placement new a new A into a?
}
Generally, you wouldn't use the storage returned by an allocation of an unrelated class A to put your B in. You don't even have to have an allocation at all
int main ()
{
char storage[sizeof(B)];
std::aligned_storage<sizeof(B), alignof(B)>::type aligned_storage;
auto b_ptr1 = new (&storage) B; // potentially unaligned
auto b_ptr2 = new (&aligned_storage) B; // guaranteed safe
// use b_ptr1, b_ptr2
b_ptr1->~B();
b_ptr2->~B();
// storage ceases to exist when main returns
}
If you do need to dynamically allocate, I would suggest wrapping the storage in a holder struct, so that you don't end the lifetime of the thing you newed.
struct B_holder
{
std::aligned_storage<sizeof(B), alignof(B)>::type storage;
B * make_B() { return new(&storage) B; }
}
int main()
{
auto holder = std::make_unique<B_holder>();
auto * B_ptr = B_holder->make_B();
// use B_ptr
B_ptr->~B();
// holder ceases to exist when main returns
}
For the most part yes.
You can however do something like this.
struct placed {
char stuff[100];
};
struct stupid {
std::aligned_storage_t<sizeof(placed), alignof(placed)> data;
~stupid() {
std::cout << "stupid gone\n";
}
};
int main() {
auto* pstupid = new stupid;
auto* pplaced = ::new( (void*)&pstupid->data ) placed;
pplaced->~placed();
auto* pstupid2 = ::new( (void*)pstupid ) stupid;
delete pstupid2;
}
but that is, as implied by the type name, pretty stupid. And exceedingly hard to make exception safe without a lot of noexcept guarantees I didn't include above.
I am also not completely certain if delete pstupid2 is legal, as it was created via placement new and not via a simple new expression.
class test
{
char *str;
public:
test(char *p_str) /**default constructor**/
{
cout<<"Default\n";
int l = strlen(p_str) + 1;
str = (l ? new char[l] : 0);
memcpy(str,p_str,l);
}
test(const test& ob) /**copy**/
{
cout<<"Copy\n";
int l = strlen(ob.str) + 1;
str = (l ? new char[l] : 0);
memcpy(str,ob.str,l);
}
test(test&& ob) /**move constructor **/
{
cout<<"Move Constructor\n";
str = ob.str;
ob.str = nullptr;
}
void my_swap(test &ob1 , test &ob2) /**swap function**/
{
swap(ob1.str , ob2.str);
}
test& operator=(test ob) /**copy is called because of pass by value **/
{
cout<<"Copy Assignment operator\n";
my_swap(*this,ob);
return *this;
/**copy is destroyed as object passed by value is destroyed just after the function returns;**/
}
~test()
{
cout<<"Destructor\n";
delete[] str;
}
void print_str()
{
cout<<str<<"\n";
}
};
The above class contains simple implementation of rule of 5 in c++.Now when a vector of this class is created as following.
int main()
{
vector<test> vec1;
vec1.push_back(test("Hi!There"));
return 0;
}
I get the following output
Default
Move Constructor
Destructor
Destructor
And when one more object is pushed into the vector like this
int main()
{
vector<test> vec1;
vec1.push_back(test("Hi!There"));
vec1.push_back(test("Hello! There"));
return 0;
}
The output is
Default
Move Constructor
Destructor
Default
Move Constructor
Copy
Destructor
Destructor
Destructor
Destructor
Now my question is why is the copy constructor called in the second case and not the first.
Thanku
Since you have 5 destructor calls instead of 4 I assume that the vector had to reallocate it's internal storage when you tried to push the second item. This means that the vector had to move the first pushed item to the newly allocated (larger) memory area. However when a vector reallocates it storage and has to transfer items from the old memory block the the new one, it may happen that the item is transferred with copy instead of move. Reason: How to enforce move semantics when a vector grows?
In your case the correct solution would be using vec1.reserve(2) (before pushing items) to avoid the unnecessary reallocation even if the reallocation happens with move. Frequent reallocation is often the target of memory usage optimization.
#include<iostream>
using namespace std;
class C
{
public:
C (){};
virtual void nothing()=0;
virtual ~C (){};
};
class A : public C
{
public:
A (){};
virtual void nothing(){};
};
class B:public A
{
public:
B(){};
void nothing(){};
};
template <class T>
void hi(T){
cout << " i am something\n";
}
template <>
void hi<A>(A)
{
cout << " I am A\n";
}
template <>
void hi<B>(B)
{
cout << " I am B\n";
}
int main ( )
{
C *array [] = {new A,new B};
hi (*array [0]);
hi (*array [1]);
delete array [0];
delete array [1];
return 0;
}
Out:
i am something
I am something
Currently I am writing a program that has to deal with
Inherited types and specialised templates. In the example above I would l would like to see
I am A
I am B
Is there a way to properly invoke the functions corresponding to the objects although I am handling a base class array? I am not sure if type checking and conversion via dynamic_cast is the most elegant solution. Note that this is just an excerpt from a larger program.
Thank you in advance
In the main routine, the three lines shown below create an array of C*.
So any element of that array is treated as a C* regardless of
what the actual type of the element is.
That is, when you pass *array [0] to the function hi(),
the function that gets called is hi(C) which resolves to
the generic hi function, not either of the specialized functions.
C *array [] = {new A,new B};
hi (*array [0]);
hi (*array [1]);
In order to make hi<A> be invoked, you either have to store the pointer
to the new object in a variable of type A* or you need to cast the
C* to an A*.
In a case like this, a virtual function of C, overridden in A and B,
may serve the purpose better.