In the following example I try to create a different object with each constructor call. I wonder how to do it by calling the constructor explicitly?
class A {
public:
static int count;
int num;
A() { num = ++count; }
};
int A::count = 0;
main() {
vector<A> x(5, A()); // all A.num values == 1
vector<A> y(5); // A.num values == 2,3,4,5,6 but no explicit constructor call
}
Related
I've looked around and only found a solution for either problem, which conflicts with the other.
I have
class A with some const member and other members that need to be initialized
class B with some constructor and a 2D array of A's
like this:
class A {
public:
A();
A(int t, int u);
const int x = 5;
private:
int _t;
int _u;
}
class B {
public:
B();
A a[50][500];
}
A::A() {
//nothing here
}
A::A(int t, int u) {
_t = t;
_u = u;
}
B::B() {
for (int i=0; i<50; i++)
for(int j=0; j<500; j++)
a[i][j] = A(i, j);
}
Now, this doesn't work because A has a const member, so the assignment fails because all the a's have already been default constructed, I obviously don't want to code 25000 initializer values in the member initializer list of B so that is out of the question.
I need the default initializer because otherwise the constructor of B will throw an error that i can't default initialize the array so i need some way to reassign the array with a newly constructed object of A.
How could I accomplish this?
This is what you want?
class A {
public:
A();
A(int t, int u);
const int x = 5;
A& operator=(const A& a);
private:
int _t;
int _u;
};
class B {
public:
B();
A a[50][500];
};
A::A() {
//nothing here
}
A& A::operator=(const A& a) {
_t = a._t;
_u = a._u;
}
A::A(int t, int u) {
_t = t;
_u = u;
}
B::B() {
for (int i=0; i<50; i++)
for(int j=0; j<500; j++)
a[i][j] = A(i, j);
}
You are just missing the = operator
If you want to avoid default-initializing your array, you can use std::vector<std::vector<A>> and populate it in B's constructor :
class A {
public:
A(t, u);
const int x = 5;
private:
int _t;
int _u;
}
class B {
public:
B();
std::vector<std::vector<A>> a;
}
A::A(t, u) {
_t = t;
_u = u;
}
B::B()
: a(50) { // a will contain 50 empty rows
for (int i=0; i<50; i++) {
a[i].reserve(500); // allocates enough space in each row for at least 500 elements
for(int j=0; j<500; j++)
a[i].emplace_back(i, j); // constructs value in-place using given arguments
}
}
Note that you don't need A's empty-parameter constructor anymore, so I have removed it.
I want to put a limit on the number of instances you can make of a class.
I have the following code:
class A {
static int cnt;
int x;
public:
A() {
cout<<"ctor called\n";
}
void* operator new(size_t size_in) {
if(cnt<=10) {
void *p=malloc(size_in);
if(p==NULL) {
throw bad_alloc();
} else {
cout<<"Memory allocation successful\n";
++cnt;
return p;
}
} else {
throw bad_alloc();
}
}
~A() {
cout<<"Cleaning up the mess\n";
}
};
int A::cnt=0;
int main() {
A *a[20];
for(int i=0;i<20;++i) {
try {
a[i]=new A();
} catch (bad_alloc &e) {
cout<<"Error in allocating memory\n";
}
}
try {
A b;
} catch (bad_alloc &e) {
cout<<"Error in allocating memory on stack\n";
}
return 0;
}
Using a static counter and overloading the new operator I am able to put a limit on the number of objects that can be created on Heap. I want to limit the number of instances created on Stack also. One way is to make constructor private and provide a public API which first checks the counter and then returns accordingly.
Is there any other way of doing this?
Is there any other way of doing this??
You may just increase and check the counter in the constructor, the object will be destroyed if you throw an exception out of it. Furthermore, you won't have to distinguish between stack and heap.
The best way to do it is to create helper template class and count objects using constructor and destructor:
class instance_limit_reached : public std::logic_error
{
public:
using logic_error::logic_error;
};
template<typename T, int MaxInst>
class LimitInstances
{
static std::atomic<int> instanceCount;
void onNewInstance() {
chekcTheLimit();
++instanceCount;
}
void chekcTheLimit() {
if (instanceCount >= MaxInst)
throw instance_limit_reached(std::string("Limit reached for ") + typeid(T).name());
}
public:
~LimitInstances() {
--instanceCount;
}
LimitInstances() {
onNewInstance();
}
LimitInstances(const LimitInstances<T, MaxInst> &) {
onNewInstance();
}
LimitInstances(LimitInstances<T, MaxInst> &&) {
onNewInstance();
}
};
Live example with field use or example with CRTP
Now there is one important question, when object is moved do you consider this as a new instance (my example) or old instance (my code needs tweaking)?
For fun, this is how I would do it: a CRTP design to be reusable with thread safe code:
template<class ToLimit,size_t MaxInstances>
class InstanceLimiter{
static inline std::atomic<int> instances=0;
private:
static increase_count(){
//memory order relaxed is sufficient because there is
//only one modification order for each atomic objects.
int actual=instances.load(std::memory_order_relaxed);
do{
if (actual>=MaxInstances) throw some_error{};
} while (instances.compare_exchange_weak(actual,actual+1,
std::memory_order_relaxed,std::memory_order_relaxed));
}
protected:
//Provide definition for default constructor, copy constructor
// and copy assignment operator so that defaulted derived special
// member function behave as expected.
InstanceLimiter(){increase_count();}
InstanceLimiter(const InstanceLimiter&){increase_count();}
InstanceLimiter& operator=(const InstanceLimiter&){
increase_count();
return *this;
}
~InstanceLimiter(){
instances.fetch_add(-1,std::memory_order_relaxed);
}
};
class A: InstanceLimiter<A,10> {
int x;
public:
A() {
//InstanceLimiter default constructor implicitly called
cout<<"ctor called\n";
}
A(int x)
//InstanceLimiter default constructor implicitly called here
:x{x}{}
//Implicitly declarer move/copy constructor/assignement implicitly calls
// the copy constructor/assignment of InstanceLimiter
~A() {
cout<<"Cleaning up the mess\n";
//Default destructor of InstanceLimiter implicitly called here.
}
};
Last but not least: if you plan to use it in real code, consider to make your class A noexcept default and move constructible by providing it a default state that does not count as an instance.
I want to limit the number of instances created on Stack also
If you want different limits for Heap and Stack object, it seem to me that the cleaner way is the one of the private constructor with friend make functions (one for heap objects and one for stack object) with counters inside the make functions.
I mean... you can write A as follows
class A
{
private:
int x;
A (int x0 = 0)
{ std::cout << "ctor called" << std::endl; }
public:
~A()
{ std::cout << "cleaning up the mess" << std::endl; }
friend A * makeAinHeap (int);
friend A makeAinStack (int);
};
and the make-in-heap function is simply
A * makeAinHeap (int x)
{
constexpr auto maxAH { 3u };
static auto ah { 0u };
if ( ++ah > maxAH )
throw std::runtime_error("no more A in Heap");
return new A{x};
}
and the analogous make-in-stack function is
A makeAinStack (int x)
{
constexpr auto maxAS { 2u };
static auto as { 0u };
if ( ++as > maxAS )
throw std::runtime_error("no more A in Stack");
return A{x};
}
You can check all with the following main()
int main ()
{
auto p1 { makeAinHeap(0) }; // OK
auto p2 { makeAinHeap(0) }; // OK
auto p3 { makeAinHeap(0) }; // OK
//auto p4 { makeAinHeap(0) }; // throw an exception
auto s1 { makeAinStack(0) }; // OK
auto s2 { makeAinStack(0) }; // OK
//auto s3 { makeAinStack(0) }; // throw an exception
delete p1;
delete p2;
delete p3;
}
I have the following piece of code:
#include<iostream>
using namespace std;
class A{
int size;
double *arr;
public:
A(int len):size(len)
{
cout<<"ctor called"<<endl;
arr=new double[size];
}
A(const A &rhs)
{
cout<<"calling copy ctor"<<endl;
size=rhs.size;
arr=new double[size];
}
~A()
{
cout<<"calling dtor"<<endl;
delete[] arr;
arr=NULL;
size=0;
}
};
A createVector()
{
cout<<"Creating object"<<endl;
A a(10);
cout<<"returning after creating object a"<<endl;
return a;
}
void foo(A v)
{
cout<<"Class A object rcvd"<<endl;
//return v;
}
int main()
{
A a=createVector();
cout<<"a has been rcvd"<<endl;
foo(a);
return 0;
}
And I have the following output:
Creating object
ctor called
returning after creating object a
a has been rcvd
calling copy ctor
Class A object rcvd
calling dtor
calling dtor
I am having trouble with createVector() function. When I return a object by value,its copy constructor should be called but I am not seeing any output between the lines
returning after creating object a
a has been rcvd
Why copy constructor has not been called??
(when I pass the rcvd object as value to foo(),Copy Constructor gets called)
#include < iostream >
using namespace std;
class A
{
public:
int x;
A(int i)
{
x= i;
cout<<"Constructor is Called "<<x<<endl;
}
~A()
{
cout<<"destructor is Called "<<x<<endl;
}
A(const A &a)
{
cout<<"in copy constructor a.x = "<<a.x<<endl;
cout<<" x = "<<x<<endl;
}
};
const A &fun(int i)
{
cout<<"in Fun"<<endl;
A t(i+1);
return(t);
}
main()
{
A *gg = new A(5);
A t = fun(2);
}
output of this is :
Constructor is Called 5
in Fun
Constructor is Called 3
destructor is Called 3
in copy constructor a.x = 0
x = 4067272
Why it is a.x=0 and x= 4067272?
Add code to initialize x in the copy constructor.
A(const A &a) : x(a.x)
//^^^^^^^^^^^^^^^ Missing code
{
cout<<"in copy constructor a.x = "<<a.x<<endl;
cout<<" x = "<<x<<endl;
}
Also,
fun returns a reference to a local variable. The reference is invalid after you return from fun. When you use A t = fun(2);, you are entering UB territory. You can't assume anything reasonable from it.
You can fix this by returning an object from fun instead of a const&.
A fun(int i)
{
cout<<"in Fun"<<endl;
A t(i+1);
return(t);
}
I have a following class foo
class foo
{
int *arr; // arr holds numbers
int sz; // size of array
public:
// Suppose I have made default and 1 parameter c'tor
foo(const foo &f)
{
sz = f.sz;
arr = new int[sz];
for(int i=0;i<sz;i++)
arr[i]=f.arr[i];
}
};
int main()
{
foo x(5); //5 is size of array
const foo y = x; //doesn't work as I haven't initialized in member-initialization list, but how to write for loop in member initialization list ?
}
So How do I write for loop in member initialization list ?
You could just use a std::vector in this caseā¦ anyways.
Typically, I will create a private static method which will perform the allocation and copy. Then the initialization list may be used:
static int* CloneInts(const foo& f) {
int* ints = new ...
...copy them from #a f.arr...
return ints;
}
Then your init-list would look like:
foo(const foo& f) : arr(CloneInts(f)), sz(f.sz) {
Have you tried constructing it with the copy constructor directly?
const foo y(x);
You should clarify your problem, because the one in the question doesn't actually exist.
The const foo y = x; line will compile and work with that copy constructor. A const object under construction isn't "const' until the constructor has completed. So the constructor body is permitted to modify the object even if the object being constructed is const.
Also note that the loop in the example isn't even modifying anything that's ever const - since the array is allocated dynamically, those array elements are modifiable even if the object itself isn't. For example, the arr pointer isn't modifiable after the ctor has completed, but arr[0] still is.
Try out the following to see both points in action:
#include <stdio.h>
#include <algorithm>
class foo
{
int *arr; // arr holds numbers
int sz; // size of array
public:
foo() : arr(0), sz(0) { puts("default ctor");}
foo(int x) : arr(0), sz(x) {
puts( "int ctor");
arr = new int[sz];
for(int i=0;i<sz;i++)
arr[i]=0;
}
foo(const foo &f)
{
puts("copy ctor");
sz = f.sz;
arr = new int[sz];
for(int i=0;i<sz;i++)
arr[i]=f.arr[i];
}
~foo() {
delete [] arr;
}
foo& operator=(const foo& rhs) {
if (this != &rhs) {
foo tmp(rhs);
std::swap( arr, tmp.arr);
std::swap( sz, tmp.sz);
}
return *this;
}
void update() const {
for(int i = 0; i < sz; i++) {
arr[i] = arr[i] + 1;
}
}
void dump() const {
for(int i = 0; i < sz; i++) {
printf("%d ", arr[i]);
}
puts("");
}
};
int main()
{
foo x(5); //5 is size of array
const foo y = x;
y.dump();
y.update(); // can still modify the int array, even though `y` is const
y.dump();
}
I think you may be confusing constructing const objects with constructing objects that have const members since those members must be initialized in the initialization list.