While it does involve reference counting, that technique is more specifically called copy-on-write.Quote:
Originally Posted by Zeus_
Printable View
While it does involve reference counting, that technique is more specifically called copy-on-write.Quote:
Originally Posted by Zeus_
So, I've been busy studying other subjects preparing for entrance exams and haven't had much time to code lately but I found some time yesterday and added a little more content to my String class. I'm having trouble overloading the >> operator for input. Any help suggesting how I should approach this will be great!
Here's the main issue part...
[EDIT]Code:std::istream& operator >> (std::istream& stream , String& _String_)
{
_String_.m_Size = 0;
delete [] _String_.m_Text;
char* Input;
stream >> Input;
_String_ = String((const char*)Input);
return stream;
}
Also, I'm creating a new string when _String_ = String((const char*)) happens. Should I be doing that or should I write an overload = for const char*? I haven't done that because a statement like A = "Hello World" (where A is a String instance) works correct as it basically is the same as A = String("Hello World").
[/EDIT]
Now, obviously I cannot do stream >> Input because Input is just a pointer to a char and has no size bound to it. I can get around this by setting a max size to it (say 256) but I don't want to do that. How would you guys suggest taking care of the input?
Here's the entire code till now...
Code:class String
{
private: /* Variables */
size_t m_Size;
char* m_Text;
private: /* Method Declarations and/or Definitions */
size_t StringLength (const char* _String_) const;
void StringCopy (const char* _String_);
public: /* Constructors and Destructor */
String ();
String (const char* _String_);
String (const String& _String_);
~String ();
public: /* Getters and Setters */
const size_t& Size (void) const;
char& At (signed int Position) const;
public: /* Method Declarations and/or Definitions */
friend std::ostream& operator << (std::ostream& stream , const String& _String_);
friend std::istream& operator >> (std::istream& stream , String& _String_);
String& operator = (const String& _String_);
char& operator [] (signed int Position) const;
};
/* Private: Method Declarations and/or Definitions */
size_t String::StringLength (const char* _String_) const
{
size_t Position = 0;
while (_String_[Position] != '\0') Position++;
return Position;
}
void String::StringCopy (const char* _String_)
{
size_t Position = 0;
while (Position < m_Size + 1)
{
m_Text[Position] = _String_[Position];
Position++;
}
}
/* Public: Constructors and Destructor */
String::String ()
: m_Size(0) ,
m_Text(nullptr)
{ }
String::String (const char* _String_)
: m_Size(StringLength(_String_)) ,
m_Text(new char [m_Size + 1])
{
StringCopy(_String_);
}
String::String (const String& _String_)
: m_Size(_String_.Size()) ,
m_Text(new char [m_Size + 1])
{
StringCopy(_String_.m_Text);
}
String::~String ()
{
delete [] m_Text;
}
/* Public: Getters and Setters */
const size_t& String::Size (void) const
{
return m_Size;
}
char& String::At (signed int Position = 0) const
{
/*
String: "Hello"
Size: 5
Indexing: 'H' 'E' 'L' 'L' 'O' '\0'
0 1 2 3 4 5
-5 -4 -3 -2 -1
*/
return operator [] (Position);
}
/* Public: Method Declarations and/or Definitions */
std::ostream& operator << (std::ostream& stream , const String& _String_)
{
return stream << _String_.m_Text;
}
std::istream& operator >> (std::istream& stream , String& _String_)
{
_String_.m_Size = 0;
delete [] _String_.m_Text;
char* Input;
stream >> Input;
_String_ = String((const char*)Input);
return stream;
}
char& String::operator [] (signed int Position) const
{
/*
String: "Hello"
Size: 5
Indexing: 'H' 'E' 'L' 'L' 'O' '\0'
0 1 2 3 4 5
-5 -4 -3 -2 -1
*/
if (Position < 0)
return ((Position > -(int)m_Size) ? m_Text[(int)m_Size + Position] : m_Text[0]);
return ((Position < (int)m_Size) ? m_Text[Position] : m_Text[(int)m_Size - 1]);
}
String& String::operator = (const String& _String_)
{
delete [] m_Text;
m_Size = _String_.m_Size;
m_Text = new char [m_Size + 1];
StringCopy(_String_.m_Text);
return *this;
}
I suggest keeping track of both size (number of elements in use, whether or not the null character is included is up to you) and capacity (number of elements for which memory has been allocated). This will allow you to more easily grow the string so as to implement operator>> for istream. You will need to parse the input yourself and reallocate as needed in a loop.
Note that you should overload operator[] for both const and non-const versions: the non-const version should return a non-const reference; the const version should either return a const reference or by value.
Your copy assignment operator is not exception-safe. You should only delete[] after allocating and copying. The right approach to do this is either the old way of implementing it through the copy constructor, destructor, and swap function, or the new way of doing a copy and move.
As for naming: identifers that begin with an underscore followed by an uppercase letter are reserved to the implementation for any use, so you should not use such names yourself.
> I suggest keeping track of both size (number of elements in use, whether or not the null character is included is up to you) and capacity (number of elements for which memory has been allocated). This will allow you to more easily grow the string so as to implement operator>> for istream. You will need to parse the input yourself and reallocate as needed in a loop.
Thanks, I'll see what I'm able to cook myself when I next sit for writing the class.
> Note that you should overload operator[] for both const and non-const versions: the non-const version should return a non-const reference; the const version should either return a const reference or by value.
Could you demonstrate in an example why a non-const reference overload should be provided? Everything seems to work fine with the const version (as far as I've tried with simple examples) as putting the const in the end just says that the overload [] will not be modifying the contents of the class member variables.
> Your copy assignment operator is not exception-safe. You should only delete[] after allocating and copying. The right approach to do this is either the old way of implementing it through the copy constructor, destructor, and swap function, or the new way of doing a copy and move.
That makes sense, the delete[] after allocation and copying. I'll see what I can do. We haven't learnt about Move Constructors so I'll hold that out for now until I learn it myself some other day....
> As for naming: identifers that begin with an underscore followed by an uppercase letter are reserved to the implementation for any use, so you should not use such names yourself.
Noted. Changed all _String_ to Str for now.
Thanks for your help! :)