Consider we create the array using this way:
T* arr = new T[num];
And now because of some reasons we understood that we need simply delete that array but without calling any T destructors.
We all know that if we write next:
delete arr;
the T destructor will be called.
If we write this:
delete[] arr;
the num destructors would be called.
Having played with pointers, you realize that new inserts before the result pointer the unsigned long long value that represents the number of allocated T instances. So we try to outwit the C++ trying to change that value to number of bytes that arr occupies and delete it as (char*) in hope that in this case the delete would not call the destructors for T instances and simply free occupied memory. So you write something like this:
typedef unsigned long long;
unsll & num = *(unsll)((char*)arr-sizeof(unsll));
num = num*sizeof(T);
delete ((char*)arr);
But that doesn't work and C++ creates the trigger breakpoint(run time error) when trying to delete this. So that doesn't work. And a lot of other playing with pointers doesn't work as at least some error(compile- or run-time) occurs. So the question is:
Is that possible to delete an array of classes in C++ without calling their destructors?
Perhaps you want ::operator delete[](arr).
(See http://en.cppreference.com/w/cpp/memory/new/operator_delete)
But this still has undefined behaviour, and is a terrible idea.
One simple way to deallocate without calling destructors is to separate allocation and initialization. When you take proper care of alignment you can use placement new (or the functionality of a standard allocator object) to create the object instances inside the allocated block. Then at the end you can just deallocate the block, using the appropriate deallocation function.
I can't think of any situation where this would be a smart thing to do: it smells strongly of premature optimization and X/Y-problem (dealing with problem X by imagining impractical Y as a solution, then asking only about Y).
A new-expression is designed to couple allocation with initialization, so that they're executed as an all-or-nothing operation. This coupling, and ditto coupling for cleanup and deallocation, is key to correctness, and it also simplifies things a lot (i.e., inside there's complexity that one doesn't have to deal with). Uncoupling needs to have a very good reason. Avoiding destructor calls, for e.g. purposes of optimization, is not a good reason.
I'm only going to address your specific question of
Is that possible to delete an array of classes in C++ without calling their destructors?
The short answer is yes.
The long answer is yes, but there's caveats and considering specifically what a destructor is for (i.e. resource clean up), it's generally a bad idea to avoid calling a class destructor.
Before I continue the answer, it should be noted that this is specifically to answer your question and if you're using C++ (vs. straight C), using this code will work (since it's compliant), but if you're needing to produce code in this way, you might need to rethink some of your design since code like this can lead to bugs/errors and general undefined behavior if not used properly.
TL;DR if you need to avoid destructors, you need to rethink your design (i.e. use copy/move semantics or an STL container instead).
You can use malloc and free to avoid constructor and destructor calls, example code:
#include <iostream>
#include <cstdio>
class MyClass {
public:
MyClass() : m_val(0)
{
this->init(42);
std::cout << "ctor" << std::endl;
}
~MyClass()
{
std::cout << "dtor" << std::endl;
}
friend std::ostream& operator<<(std::ostream& stream, const MyClass& val)
{
stream << val.m_val;
return stream;
}
void init(int val)
{
/* just showing that the this pointer is valid and can
reference private members regardless of new or malloc */
this->_init(val);
}
private:
int m_val;
void _init(int val)
{
this->m_val = val;
}
};
template < typename Iterator >
void print(Iterator begin, Iterator end)
{
while (begin != end) {
std::cout << *begin << std::endl;
++begin;
}
}
void set(MyClass* arr, std::size_t count)
{
for (; count > 0; --count) {
arr[count-1].init(count);
}
}
int main(int argc, char* argv[])
{
std::cout << "Calling new[10], 10 ctors called" << std::endl;
MyClass* arr = new MyClass[10]; // 10 ctors called;
std::cout << "0: " << *arr << std::endl;
set(arr, 10);
print(arr, arr+10);
std::cout << "0: " << *arr << std::endl;
std::cout << "Calling delete[], 10 dtors called" << std::endl;
delete[] arr; // 10 dtors called;
std::cout << "Calling malloc(sizeof*10), 0 ctors called" << std::endl;
arr = static_cast<MyClass*>(std::malloc(sizeof(MyClass)*10)); // no ctors
std::cout << "0: " << *arr << std::endl;
set(arr, 10);
print(arr, arr+10);
std::cout << "0: " << *arr << std::endl;
std::cout << "Calling free(), 0 dtors called" << std::endl;
free(arr); // no dtors
return 0;
}
It should be noted that mixing new with free and/or malloc with delete results in undefined behavoir, so calling MyClass* arr = new MyClass[10]; and then call free(arr); might not work as "expected" (hence the UB).
Another issue that will arise from not calling a constructor/destructor in C++ is with inheritance. The above code will work with malloc and free for basic classes, but if you start to throw in more complex types, or inherit from other classes, the constructors/destructors of the inherited classes will not get called and things get ugly real quick, example:
#include <iostream>
#include <cstdio>
class Base {
public:
Base() : m_val(42)
{
std::cout << "Base()" << std::endl;
}
virtual ~Base()
{
std::cout << "~Base" << std::endl;
}
friend std::ostream& operator<<(std::ostream& stream, const Base& val)
{
stream << val.m_val;
return stream;
}
protected:
Base(int val) : m_val(val)
{
std::cout << "Base(" << val << ")" << std::endl;
}
void _init(int val)
{
this->m_val = val;
}
int m_val;
};
class Child : public virtual Base {
public:
Child() : Base(42)
{
std::cout << "Child()" << std::endl;
}
~Child()
{
std::cout << "~Child" << std::endl;
}
void init(int val)
{
this->_init(val);
}
};
template < typename Iterator >
void print(Iterator begin, Iterator end)
{
while (begin != end) {
std::cout << *begin << std::endl;
++begin;
}
}
void set(Child* arr, std::size_t count)
{
for (; count > 0; --count) {
arr[count-1].init(count);
}
}
int main(int argc, char* argv[])
{
std::cout << "Calling new[10], 20 ctors called" << std::endl;
Child* arr = new Child[10]; // 20 ctors called;
// will print the first element because of Base::operator<<
std::cout << "0: " << *arr << std::endl;
set(arr, 10);
print(arr, arr+10);
std::cout << "0: " << *arr << std::endl;
std::cout << "Calling delete[], 20 dtors called" << std::endl;
delete[] arr; // 20 dtors called;
std::cout << "Calling malloc(sizeof*10), 0 ctors called" << std::endl;
arr = static_cast<Child*>(std::malloc(sizeof(Child)*10)); // no ctors
std::cout << "The next line will seg-fault" << std::endl;
// Segfault because the base pointers were never initialized
std::cout << "0: " << *arr << std::endl; // segfault
set(arr, 10);
print(arr, arr+10);
std::cout << "0: " << *arr << std::endl;
std::cout << "Calling free(), 0 dtors called" << std::endl;
free(arr); // no dtors
return 0;
}
The above code is compliant and compiles without error on g++ and Visual Studio, but due to the inheritance, both crash when I try to print the first element after a malloc (because the base class was never initialized).
So you can indeed create and delete an array of objects without calling their constructors and destructors, but doing so results in a slew of extra scenarios you need to be aware of and account for to avoid undefined behavior or crashes, and if this is the case for your code, such that you need to ensure the destructors are not called, you might want to reconsider your overall design (possibly even use an STL container or smart pointer types).
Hope that can help.
Related
class Guitars
{
private:
int serialNumber{0};
float price{0.0};
// GuitarSpecs spec{};
public:
Guitars(int serNum, float price)
{
this->serialNumber = serNum;
this->price = price;
};
Guitars(const Guitars &s)
: serialNumber{s.serialNumber}, price{s.price}
{
std::cout << "Copy" << std::endl;
};
Guitars(Guitars &&source) noexcept : serialNumber{source.serialNumber}, price{source.price}
{
source.serialNumber = NULL;
source.price = NULL;
std::cout << "Move" << std::endl;
};
int GetSerial() const { return serialNumber; };
float GetPrice() const { return price; };
void SetPrice(float x) { this->price = x; }
};
class Inventory
{
private:
list<Guitars *> *guitarList;
public:
Inventory()
{
guitarList = new list<Guitars *>;
}
void AddGuitar(int serNum, float price)
{
Guitars *x = new Guitars(serNum, price);
// Guitars x(serNum,price);
guitarList->push_back(x);
}
void Display()
{
for (auto &&i : *guitarList)
{
std::cout << i->GetPrice() << " " << i->GetSerial() << endl;
}
}
~Inventory()
{
for (auto &&i : *guitarList)
{
std::cout << i->GetSerial() << " "
<< "deleted " << std::endl;
delete i;
}
std::cout << "List is deleted" << std::endl;
delete guitarList;
}
};
int main()
{
Inventory I;
I.AddGuitar(12050, 50.23);
I.AddGuitar(10000, 20.00);
I.Display();
return 0;
}
Can someone please explain to me why is the copy constructor not called in the code above?
When I created a list of Guitar pointers on the heap along with Guitar object on the heap with a pointer pointing to them and save those pointers in Inventory list, copy constructor is not called. Why is that happening and is this one more efficient since the program is not ganna create copies of object, its created once on the heap and we save the pointer with us.
Some detailed answer, based on you talking about optimization:
Your have the following code:
list<Guitars *> *guitarList;
void AddGuitar(int serNum, float price)
{
Guitars *x = new Guitars(serNum, price);
// Guitars x(serNum,price);
guitarList->push_back(x);
}
I think your reason to use all of those pointers is to be faster. If a Guitars object would be created on the stack as usual and then be pushed back, that would create a copy, true.
What you could do instead would be to define a move operation for Guitars and move the stack object into what you create in the list, like by calling the move constructor.
But even better would be to use std::list::emplace_back, like this:
list<Guitars> guitarList;
void AddGuitar(int serNum, float price)
{
guitarList.emplace_back(serNum, price);
}
In any case, if you talk about optimality, those pointers are not good. A pointer requires additional space, and every time the data is accessed, the pointer must be dereferenced. Also, as #PaulMcKenzie wrote in the comments, this can block the compiler from optimizing for you.
Also, making a list member itself a pointer, that is going with list<Guitars*>* guitarList; or list<Guitars>* guitarList;, is also not a good idea. The only reason I see is if you want to exchange the lists of two Inventory objects, but in that case, simply call std::swap on the lists.
If you drop the pointers, note how instantly every other code of yours becomes far easier. You don't even have to define your destructor at all.
(As for the actual question you asked, like #Jarod42 already wrote, copying pointers does not copy objects.)
(By the way, if the class Guitars represents a single guitar, then I'd go for the singular, Guitar.)
Edit:
I created a small series of tests with different ways to fill the list, using Guitars mostly unmodified. (I removed the assignments of the non-pointers to NULL though.) In any way, I did the following test setup:
#include <iostream>
#include <list>
class Guitar
{
private:
int serialNumber{0};
float price{0.0};
public:
Guitar(int serNum, float price)
{
std::cout << "Base" << std::endl;
this->serialNumber = serNum;
this->price = price;
}
Guitar(const Guitar& s)
: serialNumber{s.serialNumber}, price{s.price}
{
std::cout << "Copy" << std::endl;
}
Guitar(Guitar&& source) noexcept : serialNumber{source.serialNumber}, price{source.price}
{
std::cout << "Move" << std::endl;
}
};
void test_1()
{
std::cout << "test 1" << std::endl;
std::list<Guitar*> guitarList;
Guitar* x = new Guitar(1, 2.);
guitarList.push_back(x);
std::cout << std::endl;
}
void test_2()
{
std::cout << "test 2" << std::endl;
std::list<Guitar> guitarList;
Guitar x(1, 2.);
guitarList.push_back(x);
std::cout << std::endl;
}
void test_3()
{
std::cout << "test 3" << std::endl;
std::list<Guitar> guitarList;
guitarList.push_back(Guitar(1, 2.));
std::cout << std::endl;
}
void test_4()
{
std::cout << "test 4" << std::endl;
std::list<Guitar> guitarList;
guitarList.emplace_back(1, 2.);
std::cout << std::endl;
}
int main()
{
test_1();
test_2();
test_3();
test_4();
}
The output of this is:
test 1
Base
test 2
Base
Copy
test 3
Base
Move
test 4
Base
I hope this increases further understanding about how things work here.
The tests can be found under http://www.cpp.sh/35ld6
Also, I wanted to mention, if we talk about optimization, we'd have to talk about what we optimize. Right now, we have small lists of objects with almost no content. In that case, one would not optimize at all, as we talk about nanoseconds in difference.
The cases to think about are:
A small list of big objects that are easy to move. In that case, we need to make sure that no copy constructor is called, but move would be fine.
A small list of big objects that are hard to move. In that case, we only want to use the base operator, possibly by pointers as you initially did - but emplace_back also works and makes things easier. Note that the objects being hard to move would hint at a bad design for the class.
A big list of small objects. Here we want to use as few constructors as possible, including move constructors. We also don't want to use a list of pointers, as that would give us additional 64 bits per object, and a lot of derefencing later on. In that case, emplace_back really shines.
So in other words, you can't go wrong with emplace_back.
#include <iostream>
#include <vector>
using namespace std;
struct A {
int i = 0;
};
void append(vector<A>& v) {
auto a = v.back(); // is a allocated on the stack? Will it be cleaned after append() returns?
++a.i;
v.push_back(a);
}
void run() {
vector<A> v{};
v.push_back(A{}); // is A{} created on the stack? Will it be cleaned after run() returns?
append(v);
for (auto& a : v) {
cout << a.i << endl;
}
}
int main() {
run();
return 0;
}
The code above prints as expected:
0
1
But I have two questions:
is A{} created on the stack? Will it be cleaned after run() returns?
is a allocated on the stack? Will it be cleaned after append() returns?
Update:
#include <iostream>
#include <vector>
using namespace std;
struct A {
int i = 0;
A() { cout << "+++Constructor invoked." << endl; }
A(const A& a) { cout << "Copy constructor invoked." << endl; }
A& operator=(const A& a) {
cout << "Copy assignment operator invoked." << endl;
return *this;
};
A(A&& a) { cout << "Move constructor invoked." << endl; }
A& operator=(A&& a) {
cout << "Move assignment operator invoked." << endl;
return *this;
}
~A() { cout << "---Destructor invoked." << endl; }
};
void append(vector<A>& v) {
cout << "before v.back()" << endl;
auto a = v.back();
++a.i;
cout << "before v.push_back()" << endl;
v.push_back(a);
cout << "after v.push_back()" << endl;
}
void run() {
vector<A> v{};
v.push_back(A{});
cout << "entering append" << endl;
append(v);
cout << "exited append" << endl;
for (auto& a : v) {
cout << a.i << endl;
}
}
int main() {
run();
return 0;
}
Output:
+++Constructor invoked.
Move constructor invoked.
---Destructor invoked.
entering append
before v.back()
Copy constructor invoked.
before v.push_back()
Copy constructor invoked.
Copy constructor invoked.
---Destructor invoked.
after v.push_back()
---Destructor invoked.
exited append
0
0 // I understand why it outputs 0 here. I omitted the actual work in my copy/move constructors overloads.
---Destructor invoked.
---Destructor invoked.
I updated the code in my question, adding the copy/move constructors. I found copy constructor was called 3 times in append. I understand auto a = v.back(); needs a copy, But the two other copies maybe should be avoided?
The C++ specification doesn't actually say.
With v.push_back(A{}) the A{} part creates a temporary object, which is then moved or copied into the vector, and then the temporary object is discarded.
Same with local variables, really, the "stack" is actually never mentioned by the C++ standard, it only tells how life-time should be handled. That a compiler might use a "stack" is an implementation detail.
With that said, most C++ compilers will use the "stack" to store local variables. Like for example the variable a in the append function. As for the temporary object created for v.push_back(A{}) you need to check the generated assembly code.
For the life-times, the life-time of the temporary object A{} ends as soon as the push_back function returns. And the life-time of a in the append function ends when the append function returns.
In this function
void append(vector<A>& v) {
auto a = v.back(); // is a allocated on the stack? Will it be cleaned after append() returns?
++a.i;
v.push_back(a);
}
the variable a has the automatic storage duration and is a local variable of the function. It will not be alive after exiting the function.
In this function
void run() {
vector<A> v{};
v.push_back(A{}); // is A{} created on the stack? Will it be cleaned after run() returns?
append(v);
for (auto& a : v) {
cout << a.i << endl;
}
}
again the variable v has the automatic storage duration and is a local variable of the function. When the function will finish its execution the variable will be destroyed. And all elements of the vector (that are placed in the heap) also will be destroyed due to the destructor of the vector.
Consider the following demonstrative program.
#include <iostream>
#include <vector>
struct A {
int i = 0;
};
int main()
{
std::vector<A> v;
std::cout << "&v = " << &v << "\n\n";
A a;
std::cout << "&a = " << &a << "\n\n";
v.push_back( a );
std::cout << "&v = " << &v << '\n';
std::cout << "&a = " << &a << '\n';
std::cout << "&v[0] = " << &v[0] << "\n\n";
++a.i;
v.push_back( a );
std::cout << "&v = " << &v << '\n';
std::cout << "&a = " << &a << '\n';
std::cout << "&v[0] = " << &v[0] << '\n';
std::cout << "&v[1] = " << &v[1] << "\n\n";
return 0;
}
Its output might look like
&v = 0x7ffc27288dd0
&a = 0x7ffc27288dcc
&v = 0x7ffc27288dd0
&a = 0x7ffc27288dcc
&v[0] = 0x55725232ee80
&v = 0x7ffc27288dd0
&a = 0x7ffc27288dcc
&v[0] = 0x55725232eea0
&v[1] = 0x55725232eea4
As you can see the addresses of the vector v and the object a looks similarly because they are allocated in the same outer block scope of the function and have the automatic storage duration.
&v = 0x7ffc27288dd0
&a = 0x7ffc27288dcc
And they are not changed when new values are pushed on the vector.
However the addresses of the elements of the vector as for example
&v[0] = 0x55725232ee80
&v[0] = 0x55725232eea0
&v[1] = 0x55725232eea4
have a different representation and can be changed when a new elements are added to the vector because the memory for them can be dynamically reallocated.
EDIT: After you updated your question then take into account that when a new element is added to the vector the elements of the vector can be reallocated calling the copy constructor. You can use the method reserve to reserve enough memory to avoid its reallocation and the method emplace_back.
is a allocated on the stack?
There is no such thing as "stack" storage in the language. a has automatic storage.
As far as language implementations are concerned, this typically means that the variable is probably stored in a register, or on stack, or nowhere.
Will it be cleaned after append() returns?
Yes. Automatic variables are destroyed automatically when they go out of scope.
is A{} created on the stack?
A{} is a temporary object. The language is a bit vague about the storage class of temporary objects, but it is clear about the lifetime.
Will it be cleaned after run() returns?
In this case, the temporary object is destroyed at the end of the full expression, which is before run returns.
vector elements allocated on stack?
No. Vector elements are created in dynamic storage.
Update
But the two other copies maybe should be avoided?
If your endgoal is to get a vector with two elements, you can avoid all of the copies like this:
std::vector<A> v(2);
I am looking at this pool allocator implementation. I have actually modified it a bit and my full code is:
template <class T, size_t T_per_page = 200>
class PoolAllocator
{
private:
const size_t pool_size = T_per_page * sizeof(T);
std::vector<T *> pools;
size_t count;
size_t next_pos;
void alloc_pool() {
next_pos = 0;
void *temp = operator new(pool_size);
pools.push_back(static_cast<T *>(temp));
}
public:
PoolAllocator() {
count = 0;
alloc_pool();
}
void* allocate() {
if (next_pos == T_per_page)
alloc_pool();
void* ret = pools.back() + next_pos;
++next_pos;
++count;
return ret;
}
size_t getSize() const
{
return T_per_page * (pools.size() - 1) + next_pos;
}
size_t getCount() const
{
return count;
}
size_t getCapacity() const
{
return T_per_page * pools.size();
}
T* get(size_t index) const
{
if (index >= getCount()) { return NULL; }
size_t poolIndex = index / T_per_page;
return pools[poolIndex] + (index % T_per_page);
}
~PoolAllocator() {
std::cout << "POOL ALLOCATOR DESTRUCTOR CALLED" << std::endl;
while (!pools.empty()) {
T *p = pools.back();
size_t start = T_per_page;
if (pools.size() == 1){
start = next_pos;
}
std::cout << "start: " << start << std::endl;
for (size_t pos = start; pos > 0; --pos)
{
std::cout << "pos: " << pos << std::endl;
p[pos - 1].~T();
}
operator delete(static_cast<void *>(p));
pools.pop_back();
}
}
};
template<class T>
PoolAllocator<T>& getAllocator()
{
static PoolAllocator<T> allocator;
return allocator;
}
class Node
{
private:
int id;
std::vector<float> vertices;
public:
Node() : id(42)
{
std::cout << "Node constructor called" << std::endl;
}
~Node(){ std::cout << "Node destructor called" << std::endl; }
void* operator new(size_t size)
{
std::cout << "Node operator new called" << std::endl;
return getAllocator<Node>().allocate();
}
void operator delete(void*)
{
std::cout << "Node operator delete called" << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Node* n1 = new Node();
Node* n2 = new Node();
Node* n3 = new Node();
Node* n4 = new Node();
std::cout << "Count: " << getAllocator<Node>().getCount() << " size: " << getAllocator<Node>().getSize() << " capacity: " << getAllocator<Node>().getCapacity() << std::endl;
while (true){}
return 0;
}
When I run this code in visual studio it appears to work correctly up until I close the console at which point I get an access violation error. I have tried manually calling the destructor on the allocator and it appears to work properly but I must be making a mistake somewhere. The error I get is:
Can anyone spot where I am making my mistake?
Edit 1:
Upon further investigation it will still crash even without the new Node lines in main. Seems to be related to getAllocator() method and how the destructor is called maybe? Or the fact that the allocator is static??
Edit 2:
I actually don't think it has anything to do with my allocator at all! If I try the code:
class Node2
{
private:
int x;
public:
Node2():x(42){std::cout << "Node2 constructor called" << std::endl;};
Node2(const Node2& other){ std::cout << "Node2 copy constructor called" << std::endl; };
~Node2(){ std::cout << "Node2 destructor called" << std::endl; };
};
Node2& Test(){
static Node2 myIndex;
return myIndex;
}
int _tmain(int argc, _TCHAR* argv[])
{
Test();
while (true){}
return 0;
}
It results in the same error! The plot thickens. I assumed being new to writing custom allocators that the allocator code was the issue. Still not sure why exactly this error is happening for my smaller code yet...
Writing an answer as I can't comment on the question.
I can't spot any obvious error in the last code. Are you sure you are compiling the right file and not an old unsaved version and such?
You can try to remove the line
while (true){}
And let the program just end normally.
Also, you can try to run your code in debug mode, single-stepping the instructions to find the one causing troubles.
I can spot some problems with that pool allocator.
PoolAllocator owns resources, but there's neither special copy constructor nor assignment. Most likely you should declare them deleted. And provide move-constructor and move-assignment. Though not a factor in this particular example, it may protect you from absendmindedly returning an allocator by value.
Function alloc_pool() resets next_pos before the new chunk is allocated. An exception, if ever thrown by operator new, would leave the pool in an inconsistent state.
Likewise, an exception in pools.push_back() would see the new chunk leaked. I believe std::vector<std::vector<std::byte>> would do just right, what with modern vectors being moveable. But if you absolutely want to use a vector of raw pointers, you should reserve extra space in pools, then allocate new chunk, and only then call push_back and modify the state.
Constructor of PoolAllocator may throw for no good reason.
Since allocate() method have to call alloc_pool() anyway, why calling it in the constructor? You could have a trivial noexcept constructor simply by leaving all allocation work to allocate().
PoolAllocator::allocate() and PoolAllocator::~PoolAllocator() are not symmetric. The former returns raw memory with no initialized object, while the latter assumes there's a properly constructed object in every allocated slot. That assumption is dangerous and very fragile. Imagine, for example, that T::T() throws.
It seems that getSize() and getCount() always return the same value. Is it intended?
Destructor will delete next_pos objects in the first pool, pools[0], and T_per_page objects in every other pool. But it should delete next_pos objects in the last pool.
You're in for wonderful bugs if T:~T() called from destructor of the pool ever tried to allocate another object from that very same pool. Such scenario may seem weird, but well, technically it can happen. Destructor'd better swap the current state of the pool to local variables and work on them. Repeating, if necessary.
That infinite loop in main() could spoil the destruction of global objects. Compiler could be smart enough to figure out that return is unreachable and skip the destruction part altogether.
pool_size could be a static member.
So we have a constructor that can throw an exception depending on the arguments passed to it, but we do not know how to delete the object if this occurs. Important part of the code:
try
{
GameBase *gameptr = GameBase::getGame(argc, argv);
if (gameptr == 0)
{
std::cout << "Correct usage: " << argv[PROGRAM_NAME] << " " << "TicTacToe" << std::endl;
return NO_GAME;
}
else
{
gameptr->play();
}
delete gameptr;
}
catch (error e)
{
if (e == INVALID_DIMENSION)
{
std::cout << "Win condition is larger than the length of the board." << std::endl;
return e;
}
}
catch (...)
{
std::cout << "An exception was caught (probably bad_alloc from new operator)" << std::endl;
return GENERIC_ERROR;
}
In the third line, GameBase::getGame() calls the constructor for one of the games derived from GameBase and returns a pointer to that game, and these constructors can throw exceptions. The question is, how can we then delete the (partial?) object pointed to by gameptr if this occurs? If an exception is thrown, we will exit the scope of gameptr because we leave the try block and cannot call delete gameptr.
To assess the exception safety, you need to provide more detail of the construction of the object in GameBase::getGame.
The rule is through, that if a constructor throws, the object is not created, hence the destructor is not called. Associated memory allocations are also deallocated (i.e. the memory for the object itself).
The issue then becomes, how was the memory allocated to begin with? If it was with a new GameBase(...), then there is no need to deallocate or delete the resultant pointer - the memory is deallocated by the runtime.
For clarity on what happens to the member variables that are already constructed; they are destructed on the exception of the "parent" object. Consider the sample code;
#include <iostream>
using namespace std;
struct M {
M() { cout << "M ctor" << endl; }
~M() { cout << "M dtor" << endl; }
};
struct C {
M m_;
C() { cout << "C ctor" << endl; throw exception(); }
~C() { cout << "C dtor" << endl; }
};
auto main() -> int {
try {
C c;
}
catch (exception& e) {
cout << e.what() << endl;
}
}
The output is;
M ctor
C ctor
M dtor
std::exception
If the M m_ member is to be dynamically allocated, favour a unique_ptr or a shared_ptr over a naked pointer, and allow the smart pointers to manage the object for you; as follows;
#include <iostream>
#include <memory>
using namespace std;
struct M {
M() { cout << "M ctor" << endl; }
~M() { cout << "M dtor" << endl; }
};
struct C {
unique_ptr<M> m_;
C() : m_(new M()) { cout << "C ctor" << endl; throw exception(); }
~C() { cout << "C dtor" << endl; }
};
The output here mirrors the output above.
When you write Foo* result = new Foo(), the compiler translates this to the equivalent of this code:
void* temp = operator new(sizeof(Foo)); // allocate raw memory
try {
Foo* temp2 = new (temp) Foo(); // call constructor
result = temp2;
} catch (...) {
operator delete(temp); // constructor threw, deallocate memory
throw;
}
So you don't need to worry about the allocated memory if the constructor throws. Note, however, that this does not apply to extra memory allocated within the constructor. Destructors are only called for objects whose constructor finished, so you should get all your allocations into small wrapper objects (smart pointers) immediately.
If you throw in a constructor, the object is not constructed and thus, you are responsible for the deletion of allocated resources. This goes even further! Consider this Code
int a = function(new A, new A);
It is up to the compiler in which ordering is the A allocated AND constructed. You might end up with an memory leak, if your A constructor can throw!
Edit:
Use instead
try{
auto first = std::make_unique<A>();
auto second = std::make_unique<A>();
int a = function(*first, *second);
...
Why only one object of A is created in this program? and no copy constructor is called. What is this optimization called? If this is a valid/known optimization, will it not be a trouble for multiton design pattern?
#include <iostream>
#include <stdio.h>
using namespace std;
class A
{
public:
A () {
cout << "in-- Constructor A" << endl;
++as;
}
A (const A &a) {
cout << "in-- Copy-Constructor A" << endl;
++as;
}
~A() {
cout << "out --Constructor A" << endl;
--as;
}
A & operator=(const A &a) {
cout << "assignment" << endl;
++as;
//return *this;
}
static int as;
};
int A::as = 0;
A fxn() {
A a;
cout << "a: " << &a << endl;
return a;
}
int main() {
A b = fxn();
cout << "b: " << &b << endl;
cout << "did destructor of object a in func fxn called?" << endl;
return 0;
}
Output of above program
in-- Constructor A
a: 0x7fffeca3bed7
b: 0x7fffeca3bed7
did destructor of object a in func fxn called?
out --Constructor A
Go through link http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
It will help you.
This seems to be a case of a return value optimization. This optimization is notable in the C++ world as it is allowed to change the observable behavior of the program. It's one of the few, if not the only, optimization that's allowed to do that, and it's from the days where returning copies was considered a weakness. (With move semantics and generally faster machines, this is much, much less of an issue now.)
Basically, the compiler sees that it's going to copy the object, so instead it allocates room for it on the calling frame and then builds it there instead of calling the copy constructor.