hi, everyone, i am new to C++, i tried implementing a String. and i need your help, i want to know what to improve for this class regarding performance, or everything else you think i should pay more attention to when implementing such a class for general use(of course, i think i may have to choose std::string instead...)
Thank you in advance!

Actually, this class has mixed together the basic functionalities of a String and those of a StringBuffer...

Header:

#ifndef STRING_H_
#define STRING_H_
#include <iostream>
using namespace std;
class String{
	friend ostream& operator<<(ostream& output, const String& str);
private:
	char* buffer;
	int initSize;
	int incrementSize;
	int strLength;
	int bufferSize;
public:
	String(const char* initStr = new char[128], int initSize = 128, int incrementSize = 128);
	String(const String& str);
	virtual ~String(){
		delete[] buffer;
	}
	String operator+(const String& str) const;
	String operator+(const char* str) const;
	String& operator+=(const String& str);
	String& operator+=(const char* str);
	String operator=(const String& str) const;
	String operator=(const char* str) const;
	bool operator==(const String& str) const;
	int length() {
		if(strLength == -1)
			strLength = strlen(buffer);
		return strLength;
	}
};
#endif

Implementation:

#include "String.h"
using namespace std;

String::String(const char* initStr, int initSize, int incrementSize):
	initSize(initSize), incrementSize(incrementSize){
	int strLen = strlen(initStr) + 1;
	if(strLen > 1)
		initSize = (strLen / incrementSize + 1) * incrementSize;
	buffer = new char[initSize];
	memcpy(buffer, initStr, strLen);
	strLength = -1;
	bufferSize = initSize;
}

String::String(const String& str){
		bufferSize = str.bufferSize;
		buffer = new char[bufferSize];
		strcpy(buffer, str.buffer);
		initSize = str.initSize;
		incrementSize = str.incrementSize;
		strLength = -1;
}

String String::operator+(const String& str) const{
	String tempStr = *this;
	char* paramStr = str.buffer;
	int strSize = strlen(paramStr);
	if(!strSize)
		return tempStr;
	int excessSize = strSize - (tempStr.bufferSize - tempStr.length());
	char* oldBuffer = tempStr.buffer;
	if(excessSize > 0){
		tempStr.bufferSize = tempStr.bufferSize + (excessSize / tempStr.incrementSize + 1) * tempStr.incrementSize;
		char* newBuffer = new char[tempStr.bufferSize];
		strcpy(newBuffer, oldBuffer);
		strcat(newBuffer, paramStr);
		delete [] oldBuffer;
		oldBuffer = newBuffer;
	}else{
		strcat(oldBuffer, paramStr);
	}
	tempStr.strLength = -1;
	return tempStr;
}

String String::operator+(const char* str) const{
	String tempStr = *this;
	int strSize = strlen(str);
	if(!strSize)
		return tempStr;
	int excessSize = strSize - (tempStr.bufferSize - tempStr.length());
	char* oldBuffer = tempStr.buffer;
	if(excessSize > 0){
		tempStr.bufferSize = tempStr.bufferSize + (excessSize / tempStr.incrementSize + 1) * tempStr.incrementSize;
		char* newBuffer = new char[tempStr.bufferSize];
		strcpy(newBuffer, oldBuffer);
		strcat(newBuffer, str);
		delete [] oldBuffer;
		oldBuffer = newBuffer;
	}else{
		strcat(oldBuffer, str);
	}
	tempStr.strLength = -1;
	return tempStr;
}

String& String::operator+=(const String& str) {
	char* temp = str.buffer;
	int tempSize = strlen(temp);
	if(!tempSize)
		return *this;
	int excessSize = tempSize - (bufferSize - length());
	if(excessSize > 0){
		bufferSize = bufferSize + (excessSize / incrementSize + 1) * incrementSize;
		char* newBuffer = new char[bufferSize];
		strcpy(newBuffer, buffer);
		strcat(newBuffer, temp);
		delete [] buffer;
		buffer = newBuffer;
	}else{
		strcat(buffer, temp);
	}
	this->strLength = -1;
	return *this;
}

String& String::operator+=(const char* str) {
	int tempSize = strlen(str);
	if(!tempSize)
		return *this;
	int excessSize = tempSize - (bufferSize - length());
	cout << "excessSize:" << excessSize << endl;
	if(excessSize > 0){
		bufferSize = bufferSize + (excessSize / incrementSize + 1) * incrementSize;
		char* newBuffer = new char[bufferSize];
		strcpy(newBuffer, buffer);
		strcat(newBuffer, str);
		delete [] buffer;
		buffer = newBuffer;
	}else{
		strcat(buffer, str);
	}
	cout << "buffer size:" << bufferSize << endl;
	this->strLength = -1;
	return *this;
}

String String::operator=(const String& str) const{
	return str;
}
String String::operator=(const char* str) const{
	return String(str);
}

bool String::operator==(const String& str) const{
	return strcmp(buffer, str.buffer) == 0 ? true : false;
}

ostream& operator<<(ostream& output, const String& str) {
    output << str.buffer;
    return output;
}

Recommended Answers

All 8 Replies

I think the codes was OK, but not secure yet..

hi, cikara21, thank you for replying.
Could you be more specific, and tell me how to make it more secure. I am new to the language, I don't know what kind of secure issues this class will cause...

There seem to be a few bugs in the class:
try comparing this:

String a = "abcdef";
    a = a + "ghij";
    cout << a;

with this:

String a = "abcdef";
    a+="ghij";
    cout << a;

But the most important questions is: why?
There's a perfectly fine std::string class which is used worldwide. So why create a new class?

ummm, yeah, I would use std::string as it is used worldwide...
I implemented the class just for doing some practice and looking for problems and learning from them...ah, learning from you...
so, any other bugs?

Totally unsafe: no null pointers check up at all.
Strange operator= semantics. Right (common) operator= signature:

String& String::operator=(const String&);

Try so natural p = q = s with your semantics ;)
No useful string class methods (find, substr, individuall chars accessors etc). No operator <() - impossible to place String objects in STL ordered containers. Impossible to extend this poor interface by inheritance (all members are private).
Expensive and redundant buffer allocation for default constructor case.
And so on...
None the less, it's a good start ;)

Hi, ArkM, thank you so much.
Yes, I thought intuitively that the storage allocation scheme i took was rather less efficient, but I didn't know how to make this kind of work (storage allocation & deallocation) efficient in C++, since I didn't ever need to worry about that when coding in Java(I first learned Java)...
Well, I have been reading Thinking in C++ by Bruce Eckel, and still not reached chapters covering Inheritance and STL, but I don't think Inheritance in C++ would be too much different with that in Java, at least, the ideology should be the same, right? For the features OOP has to offer, we should be encouraged to hide member data of object and operate on them through member functions, am I right?
Maybe my understanding is shallow, your corrections would be greatly appreciated.
And thank you again!

but I don't think Inheritance in C++ would be too much different with that in Java, at least, the ideology should be the same, right?

Yup.

For the features OOP has to offer, we should be encouraged to hide member data of object and operate on them through member functions, am I right?

That's how I would do it :)

Some clarification:
1. About storage allocation. I don't like that every String object declaraion involves new char[128] allocation. The default global operator new is a relatively expensive code (especially in multi-threaded environment, and in Java too). If I want to declare an array of 10000 Strings for natural language words (~6 letters average length) then default String constructors eat 1280000 bytes - why?
2.

For the features OOP has to offer, we should be encouraged to hide member data of object and operate on them through member functions, am I right?

Right. It's gospel truth but not whole truth. It supposed that your base class has all needed member function infrastructure to expand its functionality by inheritance. The class String has not such infrastructure. For example, it does not provide any non-private access to char buffer. It's possible to add contents but it's impossible to access it (some kind of a black hole). No sense in String as a base class at all and no chances to make it more useful via inheritance. In other word, you forget a wonderful access specifier - protected.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.