Вы уже получили несколько хороших ответов об ошибках в вашей функции myString::swap()
. Тем не менее, я хотел бы добавить еще один. С этой функцией что-то не так, я сначала подумал, с чего начать. Но потом я понял, что вы терпите неудачу в какой-то фундаментальной проблеме, на которую я хотел бы указать:
Как правило, функция с именем swap
должна выполнять свою задачу
- в O (1)
- без каких-либо исключений.
(Да, я знаю, есть исключения: std::tr1::array<>::swap()
. Но это должно быть очень хорошо оправдано.) Ваша реализация не удалась для обеих учетных записей. Это O (n) (strcpy
) и может вызвать исключение (new
) - и делает это без необходимости и без объяснения причин.
Когда вы посмотрите на myString
, вы увидите, что он содержит только две части данных-членов, оба из которых имеют встроенный тип. Это означает, что поменять местами два объекта этого класса действительно просто, соблюдая соглашения, упомянутые выше: просто поменяйте местами данные члена. Это так же просто, как вызов std::swap
для них:
void myString::swap(myString &from)
{
std::swap(this->stringPtr,from.stringPtr);
std::swap(this->stringLen,from.stringLen);
}
Это никогда не приведет к ошибке (замена двух указателей и двух целых чисел не может завершиться ошибкой), выполняется в O (1), очень легко понять (ну, во всяком случае, если вы получите контроль над этим обменом, в любом случае, это идиоматическая форма реализации специфичной для класса функции swap
) и состоит из двух строк кода, вызывающих что-то хорошо протестированное в стандартной библиотеке, вместо 8 строк кода, выполняющих подверженное ошибкам (и, в вашем случае, ошибочное) ручное управление памятью ,
Примечание 1: Как только вы это сделаете, вы должны специализировать std::swap
для вызова вашей реализации для вашего класса:
namespace std { // only allowed for specializing function templates in the std lib
template<>
inline void std::swap<myString>(myString& lhs, myString& rhs)
{
lhs.swap(rhs);
}
Примечание 2: Лучший (простой, безопасный для исключений и безопасный для самостоятельного присваивания) способ реализовать присвоение для вашего класса - это использовать его swap
:
myString& myString::operator=(const myString& rhs)
{
myString tmp(rhs); // invoke copy ctor
this->swap(tmp); // steal data from temp and leave it with our own old data
return *this;
} // tmp will automatically be destroyed and takes our old data with it