8 Replies - 532 Views - Last Post: 31 August 2010 - 05:24 AM Rate Topic: -----

#1 daFish  Icon User is offline

  • D.I.C Head

Reputation: 0
  • View blog
  • Posts: 61
  • Joined: 14-March 09

using Invariants()

Posted 28 August 2010 - 04:26 PM

hi,

i have a program here that works,

it just that i need some clarity on why the Invariants() method is called so many times,

here's the code...

#define DEBUG
#define SHOW_INVARIANTS
#include <iostream>
using namespace std;

#ifndef DEBUG
#define ASSERT(x)
#else
#define ASSERT(x) \
	if(! (x)) \
{ \
	cout << "ERROR!! Assert " << #x << " failed\n"; \
	cout << " on line " << __LINE__ << "\n"; \
	cout << " in file " << __FILE__ << "\n"; \
}
#endif

const int FALSE = 0;
const int TRUE = 1;
typedef int BOOL;

class String
{
public:
	// constructors
	String();
	String(const char * const);
	String(const String&);
	~String();

	char & operator[](int offset);
	char operator[](int offset) const;

	String & operator=(const String &);
	int GetLen() const { return itsLen; }
	const char * GetString() const { return itsString; }
	BOOL Invariants() const;
private:
	String(int); // private constructor
	char * itsString;
	// unsigned short itsLen;
	int itsLen;
};

// default constructor creates string of 0 bytes
String::String()
{
	itsString = new char[1];
	itsString[0] = '\0';
	itsLen = 0;
	ASSERT(Invariants());
}

// private (helper) constructor, used only by
// class methods for creating a new string of
// required size. Null filled.
String::String(int len)
{
	itsString = new char[len+1];
	for(int i=0; i<=len; i++)
		itsString[i] = '\0';
	itsLen = len;
	ASSERT(Invariants());
}

// Converts a character array to a String
String::String(const char * const cString)
{
	itsLen = strlen(cString);
	itsString = new char[itsLen+1];
	for(int i=0; i<itsLen; i++)
		itsString[i] = cString[i];
	itsString[itsLen] = '\0';
	ASSERT(Invariants());
}

// copy constructor
String::String(const String & rhs)
{
	itsLen = rhs.GetLen();
	itsString = new char[itsLen+1];
	for(int i=0; i<itsLen; i++)
		itsString[i] = rhs[i];
	itsString[itsLen] = '\0';
	ASSERT(Invariants());
}

// destructor, frees allocated memory
String::~String()
{
	ASSERT(Invariants());
	delete [] itsString;
	itsLen = 0;
}

// operator equals, frees existing memory
// then copies string and size
String& String::operator=(const String & rhs)
{
	ASSERT(Invariants());
	if(this == &rhs)
		return *this;
	delete [] itsString;
	itsLen = rhs.GetLen();
	itsString = new char[itsLen+1];
	for(int i=0; i<itsLen; i++)
		itsString[i] = rhs[i];
	itsString[itsLen] = '\0';
	ASSERT(Invariants());
	return *this;
}

// non constant offset operator
char & String::operator[](int offset)
{
	ASSERT(Invariants());
	if(offset > itsLen)
	{
		ASSERT(Invariants());
		return itsString[itsLen-1];
	}
	else
	{
		ASSERT(Invariants());
		return itsString[offset];
	}
}

// const offset operator
char String::operator[](int offset) const
{
	ASSERT(Invariants());
	char retVal;
	if(offset > itsLen)
		retVal = itsString[itsLen-1];
	else
		retVal = itsString[offset];
	ASSERT(Invariants());
	return retVal;
}

BOOL String::Invariants() const
{
#ifdef SHOW_INVARIANTS
	// cout << "Invariants Tested";
	cout << "String OK ";
#endif
	return ( (itsLen && itsString) || (!itsLen && !itsString) );
}

class Animal
{
public:
	Animal():itsAge(1),itsName("John Q. Animal")
	{ASSERT(Invariants());}
	Animal(int, const String&);
	~Animal(){}
	int GetAge() {ASSERT(Invariants()); return itsAge; }
	void SetAge(int Age)
	{
		ASSERT(Invariants());
		itsAge = Age;
		ASSERT(Invariants());
	}
	String& GetName()
	{
		ASSERT(Invariants());
		return itsName;
	}
	void SetName(const String& name)
	{
		ASSERT(Invariants());
		itsName = name;
		ASSERT(Invariants());
	}
	BOOL Invariants();
private:
	int itsAge;
	String itsName;
};

Animal::Animal(int age, const String& name):
itsAge(age),
itsName(name)
{
	ASSERT(Invariants());
}

BOOL Animal::Invariants()
{
#ifdef SHOW_INVARIANTS
	// cout << "Invariants Tested";
	cout << "Animal OK ";
#endif
	return (itsAge > 0 && itsName.GetLen());
}

int main()
{
	Animal sparky(5, "Sparky");
	cout << "\n" << sparky.GetName().GetString() << " is ";
	cout << sparky.GetAge() << " years old.";
	sparky.SetAge(8);
	cout << "\n" << sparky.GetName().GetString() << " is ";
	cout << sparky.GetAge() << " years old.\n";
	return 0;
}


here's the output...

String OK String OK String OK String OK String OK String OK String OK String OK String OK String OK
String OK String OK String OK String OK Animal OK String OK Animal OK Sparky is Animal OK 5 years old.
Animal OK Animal OK Animal OK Sparky is Animal OK 8 years old.

thats 14 calls to the String Invariant() method before the Animal Sparky is created, but WHY?

Is This A Good Question/Topic? 0
  • +

Replies To: using Invariants()

#2 Oler1s  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1395
  • View blog
  • Posts: 3,884
  • Joined: 04-June 09

Re: using Invariants()

Posted 28 August 2010 - 04:41 PM

Why don't you modify the code to throw a debug message before each assertion (that states what function was called). Also, above code is not compileable and complete, so I can't completely see what is happening.
Was This Post Helpful? 0
  • +
  • -

#3 daFish  Icon User is offline

  • D.I.C Head

Reputation: 0
  • View blog
  • Posts: 61
  • Joined: 14-March 09

Re: using Invariants()

Posted 28 August 2010 - 04:59 PM

could you show me an example of that?
Was This Post Helpful? 0
  • +
  • -

#4 Oler1s  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1395
  • View blog
  • Posts: 3,884
  • Joined: 04-June 09

Re: using Invariants()

Posted 28 August 2010 - 05:10 PM

#include <iostream>

struct A
{
    A()
    {
        std::cout << __FUNCTION__ << '\n';
    }
    ~A()
    {
         std::cout << __FUNCTION__ << '\n';
    }
};

int main()
{
    A a;
}

//Output:
A::A
A::~A



__FUNCTION__ is there in gcc and VC++ compilers. Obviously, output it before each invariant assertion.
Was This Post Helpful? 0
  • +
  • -

#5 daFish  Icon User is offline

  • D.I.C Head

Reputation: 0
  • View blog
  • Posts: 61
  • Joined: 14-March 09

Re: using Invariants()

Posted 28 August 2010 - 05:45 PM

that works great,

turns out that 11 of those Invariant() calls were from the operator[],

still seems like a high number of calls taking into account only 1 Animal object is created as you can see from the main() function,

sorry to bother you further but any idea as to why so many?
Was This Post Helpful? 0
  • +
  • -

#6 Oler1s  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1395
  • View blog
  • Posts: 3,884
  • Joined: 04-June 09

Re: using Invariants()

Posted 28 August 2010 - 05:58 PM

I'm not sure what kind of answer I can give to such a question...there are so many calls because that's what the code dictates...?

If you show the complete code, I can point out what results in each function invocation, but otherwise, if the operator[] is invoked 11 times...
Was This Post Helpful? 0
  • +
  • -

#7 daFish  Icon User is offline

  • D.I.C Head

Reputation: 0
  • View blog
  • Posts: 61
  • Joined: 14-March 09

Re: using Invariants()

Posted 28 August 2010 - 06:02 PM

thanks for you help,
that is the complete code,
Was This Post Helpful? 0
  • +
  • -

#8 Oler1s  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1395
  • View blog
  • Posts: 3,884
  • Joined: 04-June 09

Re: using Invariants()

Posted 28 August 2010 - 06:50 PM

Here's how I count the invariant calls.

Animal sparky(5, "Sparky"); There is no constructor for animal that takes a const char * as second argument. However, there is a constructor that takes a String as second argument. Furthermore, there is a constructor for String that takes a const char * as an argument. So "Sparky" is convertible to a String.

That means a string for "Sparky" must be constructed. That's one constructor call, and there will be a destructor call for this string. Two string invariant calls from constructor and destructor.

Animal constructor involves constructing itsName, by passing in a String as second argument. Invocation of String::String(const String & rhs) involves an invariant. And remember that itsName will be destructed in the end. So two more right there.

That's four you can count. What about the operator calls? If you look at the copy constructor, you see the line itsString[i] = rhs[i];, so rhs[i] is the operator call. The number of calls made corresponds with the length of the string. Since "Sparky" has 6 letters, that's 6 operator calls.

And because the constructors, destructors, and [] operators have assertions. you can see how there are so many...
Was This Post Helpful? 1
  • +
  • -

#9 daFish  Icon User is offline

  • D.I.C Head

Reputation: 0
  • View blog
  • Posts: 61
  • Joined: 14-March 09

Re: using Invariants()

Posted 31 August 2010 - 05:24 AM

thats helped me alot,
thats oler1s,
daFish,
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1