Thread: Assert: When to and when not to.

  1. #1
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968

    Assert: When to and when not to.

    Code:
    void edit(employee * _employee)
    {
    	assert (_employee !=NULL);
    	printf ("%d\n",*_employee);
    	string input;
    	int selection;
    	bool goodinput = false;		//loop conditional, input must match conditions, else continue
    	while (goodinput == false)
    	{
    		cout << "What would you like to change?" << endl		// prompt
    			 << "1. Name" << endl << "2. Payrate" << endl;
    
    		getline(cin, input);	//get input
    		stringstream(input) >> selection;	//extract selection integer
    
    		if (selection == 1)
    		{
    			cout << "Please enter a name for this employee: ";
    			getline(cin, _employee->name);
    			goodinput = true;
    		}
    		else if (selection == 2)
    		{
    			goodinput = true;
    			cout << "Please enter a pay rate for this employee (hourly): ";
    			getline(cin, _employee->payrate);	
    		}
    		else
    		{
    			goodinput = false;	// invalid selection - continue loop
    			cout << "Please enter a valid selection, 1 or 2." << endl;
    		}
    	}
    }
    Is this pretty much a good time to use assert? I'm putting it in places where normally I should probably have a control path for but don't yet, so in debug I know what's going on.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    I would go with something like
    Code:
    if ( _employee != NULL ) {
        // do stuff
    } else {
        assert(_employee != NULL);
    }
    This way, the code won't suddenly blow up in a release build should a NULL pointer unexpectedly arrive.

    I could carp about symbols beginning with underscore as well.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Also, I'm wondering... I want to put my functions that edit and create employees in a single header. Should I wrap them in a class, what would I call it? What would I call the header?
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  4. #4
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Quote Originally Posted by Salem View Post
    I would go with something like
    Code:
    if ( _employee != NULL ) {
        // do stuff
    } else {
        assert(_employee != NULL);
    }
    This way, the code won't suddenly blow up in a release build should a NULL pointer unexpectedly arrive.

    I could carp about symbols beginning with underscore as well.
    That's just my way to differentiate between local variables and passed variables, any other suggestions for that?
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  5. #5
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Code:
    This way, the code won't suddenly blow up in a release build should a NULL pointer unexpectedly arrive.
    Interesting. But the code won't do the right thing anyway. Doesn't this just mask the problem (RESUME NEXT until something goes horribly wrong a long time later)?
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > Should I wrap them in a class,
    Yes.

    > what would I call it?
    class Employee;

    > What would I call the header?
    Employee.h and Employee.cpp

    > That's just my way to differentiate between local variables and passed variables, any other suggestions for that?
    Parameters and local variables are basically the same thing as far as the language is concerned.

    For things with a wider scope than a single function, a common prefix for struct/class members and global variables (not that you should have many) seems to work.

    m_thisIsAClassMemberVariable;

    g_thisIsAGlobalVariable;

    Naming convention (programming) - Wikipedia, the free encyclopedia
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Change
    void edit(employee * _employee)
    to
    void edit(employee & _employee)

    Change

    _eployee->
    to
    _employee.

    Get rid of assert.
    Don't print addresses via printf. Don't use printf. Use std::cout or std::cerr. They will print addresses fine.
    Now what is employee? Is it a struct?
    Last edited by Elysia; 01-21-2012 at 10:22 AM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Employee is a struct, that I think I will make a class. Elysia, in my vector of employees should i store employee or *employee. Should I let the vector construct manage my memory in the heap?

    If I should not use pointers in this way, when should I use pointers? When giving different classes access to the employees do I need to give pointers, not copies of objects right?
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by Shamino View Post
    Employee is a struct, that I think I will make a class.
    Then avoid accessing its members variables directly. Use getters and setters.

    Elysia, in my vector of employees should i store employee or *employee. Should I let the vector construct manage my memory in the heap?
    This makes no sense. A vector can store employee or employee*, not *employee. A vector will always use the heap for allocation.
    What you need to worry about is not memory, but how you need to use your employees.

    If I should not use pointers in this way, when should I use pointers? When giving different classes access to the employees do I need to give pointers, not copies of objects right?
    Pointers are complicated (prone to memory leaks, can pave way for difficult sharing semantics, etc), and allocating things on the heap is much slower than simply copying small objects.
    So the thumb of rule is really: if you can get away without using pointers, then do it.
    So when do you need to use pointers? That can be difficult to answer, but generally, in your case, consider these things:
    - Are you intending to use polymorphism? Then yes, you need pointers.
    - Must several objects share the employee data (that is, if one changes an employee, must it be reflected in other objects)? If so, then use pointers. Keep in mind that it does not always make sense for objects to change employee data.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by Salem View Post
    I would go with something like
    Code:
    if ( _employee != NULL ) {
        // do stuff
    } else {
        assert(_employee != NULL);
    }
    This way, the code won't suddenly blow up in a release build should a NULL pointer unexpectedly arrive.
    That's one of those "This should never happen, but if it does" kind of things. Those bug me because it really shows that the programmer is unsure if putting the assert there is the right thing to do, i.e. they aren't sure if it will never happen. If you're sure enough that it can't happen to go and put the assert there, then why on earth would you code for the possibility that you were wrong? It just means you were never sure enough to put the assert there to begin with.

    Precondition testing is basically one of the reasons that you can never be sure that an assert is appropriate, and in that case it is fair enough.
    One option is throwing on error:
    Code:
    if (employee == NULL) throw something;
    However to avoid such an exception from being inadvertantly caught and ignored, you unfortunately do need to assert also. At work we use an ASSERT_THEN_THROW_IF_FALSE macro. Yes its long and wordy, but I don't have to explain what it does now do I

    Something allong the lines of a CHECK_PRECONDITION macro might be even better.

    Then you can save the assert for things which you know for sure are not going to be false.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  11. #11
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Lol Elysia, I don't know the difference between employee* and *employee, I may have at one point.

    I'm not sure if polymorphism would really be applicable in this project, simply because of it's scope. Perhaps eventually if I want a dynamic database that can hold all kinds of data types and sort and whatnot, something more re-usable. I think I'm going to cut out the pointers for now, and then maybe later add polymorphism to differentiate between departments and whatnot, or salaried/hourly work.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    employee* is a pointer to an employee object. *employee is not a valid type.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #13
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    Quote Originally Posted by Shamino View Post
    That's just my way to differentiate between local variables and passed variables, any other suggestions for that?
    Add the "_" at the end of the variable name instead.
    Leading underscores on variable names tend to be reserved for compiler and library users.

    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  14. #14
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    I've made some adjustments according to the responses to the thread, thanks for your input everyone!

    Employee.h:
    Code:
    #ifndef EMPLOYEE_H
    #define EMPLOYEE_H
    #include <string>
    using namespace std;
    
    class employee
    {
    public:
    	employee(string _name, string _payrate)
    	{
    		name = _name;
    		payrate = _payrate;
    	}
    
    	string& get_name()
    	{
    		return name;
    	}
    
    	string& get_payrate()
    	{
    		return payrate;
    	}
    	void edit()
    	{
    		string input;
    		int selection;
    		bool goodinput = false;		//loop conditional, input must match conditions, else continue
    		while (goodinput == false)
    		{
    			cout << "What would you like to change?" << endl		// prompt
    				 << "1. Name" << endl << "2. Payrate" << endl;
    
    			getline(cin, input);	//get input
    			stringstream(input) >> selection;	//extract selection integer
    
    			if (selection == 1)
    			{
    				cout << "Please enter a name for this employee: ";
    				getline(cin, name);
    				goodinput = true;
    			}
    			else if (selection == 2)
    			{
    				goodinput = true;
    				cout << "Please enter a pay rate for this employee (hourly): ";
    				getline(cin, payrate);	
    			}
    			else
    			{
    				goodinput = false;	// invalid selection - continue loop
    				cout << "Please enter a valid selection, 1 or 2." << endl;
    			}
    		}
    	}
    
    private:
    	string name;
    	string payrate;
    };
    
    #endif
    Experimentations.cpp (main)
    Code:
    // Experimentations.cpp : main project file.
    
    #include "stdafx.h"
    #include <iostream>
    #include <string>
    #include <sstream>
    #include <vector>
    #include <assert.h>
    #include "Employee.h"
    using namespace std;
    
    vector<employee> employees;
    
    employee create()
    {
        cout << "Please enter the new employee's name: ";
        string name;
        getline(cin, name);
        cout << "Please enter the new employee's payrate: ";
        string payrate;
        getline(cin, payrate);
        employee new_employee(name, payrate);
    	return new_employee;
    }
    
    employee & get_employee(string name)
    {
    	for (unsigned int i = 0; i < employees.size();)
    	{
    		if (name.compare(employees[i].get_name()) == 1)
    		{
    			return employees[i];
    		}
    		else
    		{
    			i++;
    		}
    	}
    	throw;
    }
    
    void list_employees(vector<employee> & employees)
    {
    	for (unsigned int i = 0; i < employees.size(); i++)
    	{
    		cout << employees[i].get_name() << endl;
    	}
    }
    
    int main()
    {
    	int selection;
    	string input;
    	bool goodinput = false;
        while (goodinput == false)
    	{
    		cout << "Welcome to the employee database, what would you like to do?" << endl		// prompt
    			 << "1. Add an employee" << endl << "2. Modify an employee" << endl;
    
    		getline(cin, input);	//get input
    		stringstream(input) >> selection;	//extract selection integer
    
    		if (selection == 1)
    		{
    			goodinput = true;
    			employees.push_back(create());
    		}
    		else if (selection == 2)
    		{
    			cout << "Enter the name of the employee you'd like to edit: ";
    			getline(cin, input);
    			get_employee(input).edit();
    			goodinput = true;
    		}
    		else
    		{
    			goodinput = false;	// invalid selection - continue loop
    			cout << "Please enter a valid selection, 1 or 2." << endl;
    		}
    	}
        return 0;
    }
    I'm not quite sure how to logically arrange the functions that actually handle the employees vector. I'm thinking about making menu objects to simplify that aspect of programming this thing, any suggestions?
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    This should not go in a header, except within a local scope:
    Code:
    using namespace std;
    Otherwise, the using directive will apply to all files that include the header. With the same reasoning, you should not place a using directive before a header inclusion. This also applies to using declarations (e.g., using std::string; ).

    This works:
    Code:
    employee(string _name, string _payrate)
    {
        name = _name;
        payrate = _payrate;
    }
    but it is better to take the arguments by const reference and use the constructor initialiser list:
    Code:
    employee(const std::string& _name, const std::string& _payrate) : name(_name), payrate(_payrate) {}
    This:
    Code:
    string& get_name()
    {
        return name;
    }
    Allows stuff like:
    Code:
    employee x("Alice", "hourly");
    x.get_name() = "Bob";
    And forbids stuff like:
    Code:
    const employee x("Alice", "hourly");
    std::cout << x.get_name() << std::endl;
    This might be your intention, but otherwise it should be:
    Code:
    const std::string& get_name() const
    {
        return name;
    }
    Your employee::edit member function is not a good choice for a member function. You can choose to make employee objects immutable in that once you have created them with a particular name and payrate, those member variables cannot be changed, or you can provide member functions to allow these member variables to be changed. Then, the function that interacts with the user to get the name and payrate would be a non-member function.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Assert/Macro
    By tempster09 in forum C Programming
    Replies: 15
    Last Post: 12-17-2009, 10:13 PM
  2. assert
    By George2 in forum C Programming
    Replies: 1
    Last Post: 10-22-2007, 03:17 AM
  3. Assert
    By Shamino in forum C++ Programming
    Replies: 8
    Last Post: 01-24-2006, 11:02 AM
  4. How to use assert?
    By jjbuchan in forum C Programming
    Replies: 2
    Last Post: 11-11-2005, 01:40 PM
  5. assert
    By ammar in forum C++ Programming
    Replies: 1
    Last Post: 10-19-2002, 08:17 AM