Linked list interface, implementation and driver file

Hello,

I am having difficulty calling the constructor in interface portion of my program. I get the error: no matching function for call to ‘Node::Node(int, NULL)’ when I try to call it on line 26 within the main function. Any suggestions?

code:
interface: http://ideone.com/VgmP15
implementation: http://ideone.com/rui6f4
main file: http://ideone.com/2rJtS5

Thanks in advance for any input to this problem.
closed account (S6k9GNh0)
1. Make a test case.
2. Use a more modern compiler.
3. Do NOT mix "new" and "delete" with "free". Big no no.
Please expain your reasoning.

What unit testing framework do you recommend, if any?
compiler is up to date: gcc version 4.7.2
why not mix these operations?
> 1. Make a test case.

You don't need a complex unit testing framework. Write some code that does something and then assert that it has actually done it as you expected.

> 2. Use a more modern compiler.

Not sure what is meant by this. Maybe use a C++11 compiler, like g++ 4.8.1?

> 3. Do NOT mix "new" and "delete" with "free". Big no no.

This is because you don't know how ::operator new() is implemented. It might use malloc(), then again it might not. Do it right. Use delete head; and spare yourself the aggravation.
I get the error: no matching function for call to ‘Node::Node(int, NULL)

Where is your compiler picking up the definition of NULL? Is it just a #define of 0?

When I try to compile you code with GCC 4.7.1, NULL is not defined. I also get a number of other errors:

BUILDING list_test_gcc.exe...

look for cpp files...
-> list.cpp
-> main.cpp

look for c files...

found 2 file(s)

invoke the compiler...
list.cpp: In member function 'Node* Node::searchElem(Node*, int)':
list.cpp:24:61: error: 'NULL' was not declared in this scope
list.cpp:30:12: error: 'NULL' was not declared in this scope
list.cpp: At global scope:
list.cpp:61:5: error: prototype for 'int Node::getValue() const' does not match
any in class 'Node'
list.h:23:7: error: candidate is: int Node::getValue()
list.cpp:67:7: error: prototype for 'Node* Node::getNext() const' does not match
 any in class 'Node'
list.h:24:9: error: candidate is: Node* Node::getNext()
list.cpp: In member function 'Node* Node::searchElem(Node*, int)':
list.cpp:31:1: warning: control reaches end of non-void function [-Wreturn-type]

list.h: In function 'int main()':
list.h:31:7: error: 'int Node::value' is private
main.cpp:42:19: error: within this context
list.h:32:9: error: 'Node* Node::next' is private
main.cpp:43:18: error: within this context
Build failed! :-(


Regarding delete versus free...

In addition to the possibility that free (and malloc) might use a different underlying memory allocation mechanism to delete (and new), free (and malloc) do not handle destruction (and construction). So if you allocate with new, you need to free with delete, to ensure that everything is always cleared up correctly.

You can probably get away with calling free on a pointer allocated with new when using a type which doesn't have members which point at heap memory, as there is nothing for the destructor to do. But only if new uses malloc. And even then it is better to always use delete to keep things consistent.

In your case, the comment by your free call suggests that you might expect the whole list (head and all it points at) to be deleted when you free the head (the "list structure" means all the list nodes, to me.) That does require the use of delete, to fire the chain of destructors, and also for you to provide a destructor which frees the next node (which I see is absent.)

Finally, you're not even allocating the head node on the heap using new or even malloc; it's a stack variable (headNode). These should not be explicitly freed in any way; they are cleaned up automatically when the stack is popped as part of the function return sequence.

Andy

PS If it's the MinGW version of GCC, then 4.7.2-1 is the latest version available at the regular download site:
http://sourceforge.net/projects/mingw/files/MinGW/Base/gcc/Version4/

(Is a newer version available elsewhere?)
Last edited on
Nice catch re stack var. I wasn't paying that much attention to the main code. Also quite correct about not calling the destructor. That is hugely bad.

As for builds, well you could check here http://gcc.gnu.org/gcc-4.8/buildstat.html for binary test runs. Or you could try and build your own as in the links on the last line of http://gcc.gnu.org/gcc-4.8/ state: To obtain GCC please use...
@AdrianH

Unfortuately, I don't the gcc.gnu.org lot deal with MinGW -- well, there's no mention of MinGW (or CYGWIN) in the build status list. :-( Of course, as you say, I could build it myself.
http://gcc.gnu.org/gcc-4.8/buildstat.html

@ElectroStatik

Regarding testing...

What unit testing framework do you recommend, if any?

I think the best framework to start with would be your own. It would be a good learning exercise, from a coding point of view, and will help you make up your mind up about what you want in a test framework for when you "trade up" later.

AdrianH mentions assert; the problem with the standard C++ version
http://www.cplusplus.com/reference/cassert/assert/
is that it will usually stop the program (ready for a debugger to be attached) when the assert condition evaluates to false. This means you can't run a set of tests, unless you're running under a debugger and repeatedly hit "go".

Instead, you should write your own "test assert" which reports the failure, and probably aborts the current test case, but allows the test program to go on to run other test cases.

As a challenge you should make your micro-framework complete enough -- e.g. asserts, result reporting, basic control (run all test/run a single, selected test/..), logging -- for you to write basic tests with minimal effort.

Andy

PS There are non-standard ways of controlling how assert behaves (for the Microsoft CRT, you have _CrtSetReportMode, etc), but "proper" test frameworks generally all use their own, custom asserts.
Last edited on
Actually Andy, what I said was 'Write some code that does something and then assert that it has actually done it as you expected.' which means check to ensure that it has done what you expected. Yes there is an assert() function (well, macro) but this is only one way to assert that something is true or not. A simple if is an assertion mechanism.

1
2
3
4
5
if (X) {
  doY();
} else {
  doZ();
}


In that example, doY() is executed only when X is asserted to be true, otherwise doZ() is called.

Testing using the assert() macro is useful, even if it terminates the application as it states that something has gone horribly wrong that cannot be recovered from. I.e. it is outside of normal boundary conditions, so the programme has no sane way of handling or correcting for this. That's why the stopping of an attached the debugger, or the execution and attaching of a debugger, or the termination of the application is the result of a failed assertion using the assert() macro.

If something is outside of normal conditions but inside of exceptional conditions occurs, using exceptions is the way to go using the key words try/catch/throw. But that assumes that you can handle the exception, otherwise the programme will again terminate.

What a test suite can do is somewhat automate this process, but I've not found any general test suite that actually addresses all problems so using the "roll your own" is generally what is used. This comprises of a test function (usually a static function in the class you want to test) which runs some basic tasks that you expect your class to be able to handle and then verify that the class has handled each correctly. This can be done using an assert() if there is only one task to test or if the tasks depend on one another (there's no point in testing multiple tasks if they are dependent on the previous tasks done since if a task fails then any tests after that are invalid anyway). If the tasks are independent of each other, and you want to test all of them in one execution, then using the assert() macro is not the way to go.

Oh, one other thing. Though the assert() macro is in the <assert.h> header, there is nothing magical about it. You can roll your own assert() macro to make it do whatever you want it to. The <assert.h> file is mostly for convenience.
Last edited on
Topic archived. No new replies allowed.