Allocating array seg faults - Documented source provided

So I am trying out new, interesting things with the C++ language.

In the advanced section of a book I were reading last night I came across a function that would return an Object pointer from a new statement, which was then used to init an Object. The object were deleted by a function that would take an Object pointer as arg.

SOURCE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <string>

class Obj
{
public:
		Obj() { ObjID = OID; ++OID; }
		~Obj() {}
		static int OID;
		int GetID() { return ObjID; }
private:
	int ObjID;
};

int Obj::OID = 0;


Obj* CreateObj()
{
	Obj *o;
	try
	{
		o = new Obj;
		if(o == nullptr) throw "Could not create Obj";
		else std::cout << "Creating Obj @ " << o << "\n";
	}
	catch(std::string s) { std::cout << s << "\n"; }
	
	return o;
}

void DeleteObj(Obj *o)
{
        try
	{
		if(o == nullptr) throw "Unable to delete null pointer";
		else
		{
			std::cout << "Deleting Obj @ " << o << "\n";
			delete o;
			o = nullptr;
		}
	}
	catch(std::string s) { std::cout << s << "\n"; }
}


For as far as my mind goes...

CreateObj() returns the address of a newly allocated block of memory containing an Obj. DeleteObj(Obj*) takes a pointer to the newly allocated block and deletes it, then assigns the pointer to nullptr.


I'm sure someone has spotted the error already before I give the main program ( I hope ).

In my main program this code doesn't throw the DeleteObj(Obj*) nullptr error.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        // Create two objects
	Obj *Obj1 = CreateObj();
	Obj *Obj2 = CreateObj();
	
	// Print them
	Print(Obj1);
	Print(Obj2);
	
	// Delete them
	DeleteObj(Obj1);
	DeleteObj(Obj2);
	
	// ^^^^ Everything seems okay up to this point
	
	// Test throw	----> ERROR! Catch never gets called
	DeleteObj(Obj1);
	Print(Obj1);//	----> According to values the Obj gets deleted, or at least something happens to it 



Further more this loop gets a runtime segmentation fault.

1
2
3
4
5
6
7
8
9
10
11
12
13
       // This seg faults, trying to assign the same memory as previous Obj's
	Obj *ObjArray[10];
	for(int i = 0; i < 10; i++)
	{
		ObjArray[i] = CreateObj();
	}
	// DOESN'T REACH HERE
	for(int i = 0; i < 10; i++)
	{
		Print(ObjArray[i]);
		DeleteObj(ObjArray[i]);
	}
	return 0;


Object Creation:
Creating Obj @ 0x82a8008
Creating Obj @ 0x82a8018

Object Print:
Obj ID = 0	Address = 0x82a8008
Obj ID = 1	Address = 0x82a8018

Object Delete:
Deleting Obj @ 0x82a8008
Deleting Obj @ 0x82a8018

Re-Delete Object 1: Delete-Catch and Print-catch not called
Deleting Obj @ 0x82a8008
Obj ID = 137003024	Address = 0x82a8008

Create Array:
Creating Obj @ 0x82a8008 - Why are the addresses the same as before?
Creating Obj @ 0x82a8018 - This 16 byte incrementation tells
Creating Obj @ 0x82a8008 - me the function is assigning new memory?
Segmentation fault



Much appreciation to those that take a look.

P.S - Something I should mention is that my gcc compiler has been acting strange as of late. It were able to compile binaries that didn't even have the right header included ( In this program I forgot to add the <string> header before declaring std::string, yet it still compiled. Similar things were happening yesterday. )
Last edited on
new does not return nullptr on failure, it throws an exception
there is no problem with delete a null pointer

> DeleteObj(Obj*) takes a pointer to the newly allocated block and deletes it,
> then assigns the pointer to nullptr.
the last part is incorrect. It modifies a local copy of the pointer, kind of useless.
that's why your program doesn't throw

you are deleting the same pointer twice, and later access an invalid pointer
don't do that, it produces undefined behaviour.


I don't see a reason for the array to fail, but it may be that you just corrupted things earlier.


> It were able to compile binaries that didn't even have the right header included
the header gets included by other headers
don't rely on that behaviour
Last edited on
Thanks for the reply.

new does not return nullptr on failure, it throws an exception
there is no problem with delete a null pointer


According to: http://www.cplusplus.com/forum/beginner/17898/


If "new" fails, does it return a null pointer?

Only if you use the nothrow version:

Node* listNode = new(nothrow) Node(value);



This is now fixed?

1
2
3
o = new(std::nothrow) Obj;
if(o == nullptr) throw "Could not create Obj";
else std::cout << "Creating Obj @ " << o << "\n";


As for deleting a nullptr, I know it's okay too. I just wanted to make sure the delete was working okay, which it seems it's not.

Also yes I know I delete it twice and access it. In the real world it can happen, I was trying to defend against it if the arg to print was a nullptr. If that makes sense?

Thanks for the clear up on changing a local copy of the pointer, how do I change the actual pointer to nullptr? and not a local copy. Thanks in advance.
Thanks to a member of the IRC the problem is fixed.

The DeleteObj() function had to take a pointer to a pointer.


Unneeded throws have been taking out. Fixed source below for anyone else who will try this.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <iostream>
#include <string>

class Obj
{
public:
		Obj() { ObjID = OID; ++OID; }
		~Obj() { --OID; }
		static int OID;
		int GetID() { return ObjID; }
private:
	int ObjID;
};

int Obj::OID = 0;


Obj* CreateObj()
{
	return new Obj;
}

void DeleteObj(Obj** o)
{
			delete *o;
			*o = nullptr;
}

void Print(Obj* o)
{
	try
	{
		if(o == nullptr) throw "Cannot print null pointer";
		else std::cout << "Obj ID = " << o->GetID() << "\tAddress = " << o << "\n";
	}
	catch(const char* s) { std::cout << s << "\n"; }
}

int main()
{
	// Create two objects
	Obj *Obj1 = CreateObj();
	Obj *Obj2 = CreateObj();
	
	// Print them
	Print(Obj1);
	Print(Obj2);
	
	// Delete them
	DeleteObj(&Obj1);
	DeleteObj(&Obj2);
	
        DeleteObj(&Obj1);
	Print(Obj1);//	----> Throws exception
	
	Obj *ObjArray[10];
	for(int i = 0; i < 10; i++)
	{
		ObjArray[i] = CreateObj();
	}

	for(int i = 0; i < 10; i++)
	{
		Print(ObjArray[i]);
		std::cout << "Deleting Obj @" << ObjArray[i] << "\n";
		DeleteObj(&ObjArray[i]);
	}
	return 0;
}
Last edited on
> If "new" fails, does it return a null pointer?
> Only if you use the nothrow version.

Evaluation of the new expression can fail for a variety of reasons.

1. Evaluation of the expression new (std::nothrow) A[sz] may fail if sz is invalid; in this case, the allocation function operator new[] is not called; the implementation will throw an exception of type std::bad_array_new_length.

2. Evaluation of the expression new (std::nothrow) A( /*...*/ ) may fail if the allocation function could not allocate the memory. In this case, because of std::nothrow, it returns (void*)nullptr and (A*)nullptr is the result of the evaluation.

3. Evaluation of the expression new (std::nothrow) A( /*...*/ ) may fail if the the allocation function returned a non-null pointer, but the object initialisation code throws an exception. The deallocation function is called to release the memory and the exception that was thrown is propagated to the context of the new-expression.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <new>
#include <stdexcept>

struct A
{
    A( int i ) { if( i > 100 ) throw std::invalid_argument( "A::A(int) - invalid constructor argument" ) ; }
};

int main()
{
    try
    {
        int* p = new (std::nothrow) int[-1] ;
        delete p ;
    }
    catch( const std::exception& error )
    {
        std::cerr << "new failed, exception was thrown. what: " << error.what() << '\n' ;
    }

    try
    {
        A* p = new (std::nothrow) A(500) ;
        delete p ;
    }
    catch( const std::exception& error )
    {
        std::cerr << "new failed, exception was thrown. what: " << error.what() << '\n' ;
    }
}

g++-4.9 -std=c++11 -Wall -Wextra -pedantic-errors -O3 main.cpp -o test && ./test
new failed, exception was thrown. what: std::bad_array_new_length
new failed, exception was thrown. what: A::A(int) - invalid constructor argument

http://coliru.stacked-crooked.com/a/dfc0bcd9d03c6d7c



> throw "Could not create Obj";

This will not be caught by catch(std::string s). It can be caught by catch( const char* ).

Perhaps something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Obj* CreateObj()
{
    try 
    { 
        auto p =  new Obj ; 
        std::clog << "created object at " << p << '\n';
        return p ;
    }

    catch( const std::bad_alloc& )
    { std::cerr << "could not create object: allocation failed\n" ; }

    catch( ... )
    { std::cerr << "could not create object: initialisation failed\n" ; }

    return nullptr ;
}
Last edited on
Thank you ever so much for the explanations.

I'll start of with the small stuff,

I realised string could not be used and changed to const char, I am liking this const std::exception code, much easier to handle.

I am liking your function, looks nice and smooth. Not sure about the auto and ... keywords though
auto http://www.stroustrup.com/C++11FAQ.html#auto

If an ellipsis (...) is used as the parameter of catch, that handler will catch any exception no matter what the type of the exception thrown. This can be used as a default handler that catches all exceptions not caught by other handlers
http://www.cplusplus.com/doc/tutorial/exceptions/
Thanks for the material.


The second time I have looked at the system monitor checking how much memory usage this has, initialising 1 million classes get's a respectable 20 mb, however when doing the delete process, the memory stayed the same? Like it wasn't being freed.
There is no way to know how much memory a program is using. What you see from e.g. task manager is just an estimate. Use a real memory leak detection program to find out what's really going on.

See also JLBorges' post below.
Last edited on
> however when doing the delete process, the memory stayed the same? Like it wasn't being freed.

From the GNU C library manual:
Occasionally, free can actually return memory to the operating system and make the process smaller. Usually, all it can do is allow a later call to malloc to reuse the space. In the meantime, the space remains in your program as part of a free-list used internally by malloc.
http://www.gnu.org/software/libc/manual/html_node/Freeing-after-Malloc.html

Examine the memory usage of the process for a second time after creating another 1 million objects.
Thanks for that again, I figured it out after re-reading this.



Creating Obj @ 0x82a8008 - Why are the addresses the same as before?
Creating Obj @ 0x82a8018
Creating Obj @ 0x82a8008


According to that info it re-initialised memory at those slots that new made, then it seemed to loop to the next available slot which was already in use, I guess that's why it seg faulted in the first place.

Been a great learning experience.


Another question though,

I am using valgrind and perf for testing this code, the output is complete jargon to me, is there anything I should be looking for in hundreds of lines of numbers?
Topic archived. No new replies allowed.