Моя первая реализация String
От: roma_k Украина  
Дата: 08.07.04 11:11
Оценка:
Оцените пожалуйста, интересны все мои ошибки, особенно в реализации операторов !!!
// Заголовок 
class nvString
{
public:
    // constructor
    nvString();

    // Construct a string from a char pointer
    nvString(const char* inStr);

    // Copy-constructor
    nvString(const nvString& inStr);

    // destructor
    virtual ~nvString();

    // Type cast to char pointer
    inline operator const char *() const
    { return m_buffer; }

    // Indexing operator
    inline char operator[](int i) const
    { return m_buffer[i]; }

    // Char pointer atribuition operator
    nvString& operator=(const char* inStr);

    // Atribuition operator
    nvString& operator=(const nvString& inStr);

    // Concatenation operator with a char pointer
    nvString operator+(const char* inStr);

    // Concatenation operator
    nvString operator+(const nvString& inStr);

    // Self-concatenation operator with a char pointer
    void operator+=(const char* inStr);
    
    // Self-concatenation operator
    void operator+=(const nvString& inStr);

    void Clear(void);
    
    // Find a sub-string in the string
    inline int Find(const char *str) const
    { 
        char *pos=strstr(m_buffer,str);
        if (pos == 0)
            return -1;
        return (int)(pos-m_buffer); 
    }

    // Find the first occurrence of a character in the string
    inline int Find(char c) const
    { 
        char *pos = strchr(m_buffer,c);
        if (pos == 0)
            return -1;
        return (int)(pos-m_buffer); 
    }

    // Find the last occurrence of a character in the string
    inline int FindLast(char c) const
    {
        char *pos = strrchr(m_buffer,c);
        if (pos == 0)
            return -1;
        return (int)(pos-m_buffer); 
    }

    // Change the 'i'-th character of the string
    inline void SetChar(int i,char c)
    { 
        if (i < (int)strlen(m_buffer)) 
            m_buffer[i] = c;
    }

    // Crop the first 'n' characters of the string
    inline void CropBegin(int n)
    { 
        if (n < (int)strlen(m_buffer))
        {
            strcpy(m_buffer,&m_buffer[n]);
        }
    }

    // equal compare operator
    inline int operator==(const char *str) const 
    { return strcmp(m_buffer,str)==0; }

    inline int operator!=(const char *str) const 
    { return strcmp(m_buffer,str)!=0; }

    inline int operator>(const char *str) const 
    { return strcmp(m_buffer,str)>0; }

    inline int operator<(const char *str) const 
    { return strcmp(m_buffer,str)<0; }

    inline int operator>=(const char *str) const 
    { return strcmp(m_buffer,str)>=0; }

    inline int operator<=(const char *str) const 
    { return strcmp(m_buffer,str)<=0; }

    // Compare with a char pointer
    inline int Compare(const char *str) const
    { return strcmp(m_buffer,str); }

    // Compare the first 'n' characters of the string with a char pointer
    inline int Compare(const char *str,int n) const
    { return strncmp(m_buffer,str,n); }

    // Compare with a char pointer, case-insensitive flavour
    inline int CompareNoCase(const char *str) const
    { return stricmp(m_buffer,str); }

    // Change all characters to lower-case
    inline void ToLower()
    { strlwr(m_buffer); }

    // Change all characters to upper-case
    inline void ToUpper()
    { strupr(m_buffer); }

    // Return the length of the string in bytes
    inline int Length() const
    { return (int)strlen(m_buffer); }

private:
    char *m_buffer;
};

// тело
char* StrDuplicate(const char *str)
{
    char *strRet = new char[strlen(str)+1];
    assert(strRet);
    strcpy(strRet, str);
    return strRet;
}

nvString::nvString()
{
    m_buffer = StrDuplicate("");
}

nvString::nvString(const char* inStr)
{
    assert(inStr);
    m_buffer = StrDuplicate(inStr);
}

nvString::nvString(const nvString& inStr)
{
    assert(inStr.m_buffer);

    m_buffer = StrDuplicate(inStr.m_buffer);
}

nvString::~nvString()
{
    SafeArrayDelete(m_buffer);
}

void nvString::Clear(void)
{
  operator=("");
}

nvString& nvString::operator=(const char* inStr)
{
    assert(inStr);

    char *str = StrDuplicate(inStr);
    SafeArrayDelete(m_buffer);
    m_buffer = str;

    return *this;
}

nvString& nvString::operator=(const nvString& inStr)
{
    assert(inStr.m_buffer);

    char *str = StrDuplicate(inStr.m_buffer);
    SafeArrayDelete(m_buffer);
    m_buffer = str;

    return *this;
}

nvString nvString::operator+(const char* inStr)
{
    assert(inStr);

    nvString ret;

    int    len = (int)strlen(m_buffer) + (int)strlen(inStr)+1;
    char *str = StrDuplicate(m_buffer);
    assert(str);

    SafeArrayDelete(ret.m_buffer);

    ret.m_buffer = new char [len];
    assert(ret.m_buffer);

    strcpy(ret.m_buffer, str);
    strcat(ret.m_buffer, inStr);
    SafeArrayDelete(str);

    return ret;
}

nvString nvString::operator+(const nvString& inStr)
{
    assert(inStr.m_buffer);

    nvString ret;

    int    len = (int)strlen(m_buffer) + (int)strlen(inStr.m_buffer)+1;
    char *str = StrDuplicate(m_buffer);
    assert(str);

    SafeArrayDelete(ret.m_buffer);

    ret.m_buffer = new char [len];
    assert(ret.m_buffer);

    strcpy(ret.m_buffer, str);
    strcat(ret.m_buffer, inStr.m_buffer);
    SafeArrayDelete(str);

    return ret;
}

void nvString::operator+=(const char* inStr)
{
    assert(inStr);

    int    len = (int)strlen(m_buffer) + (int)strlen(inStr)+1;
    char *str = StrDuplicate(inStr);
    char *strOld = StrDuplicate(m_buffer);

    SafeArrayDelete(m_buffer);
    m_buffer = new char[len];
    strcpy(m_buffer,strOld);
    strcat(m_buffer,inStr);
    SafeArrayDelete(str);
    SafeArrayDelete(strOld);
}

void nvString::operator+=(const nvString& inStr)
{
    assert(inStr.m_buffer);

    int    len = (int)strlen(m_buffer) + (int)strlen(inStr.m_buffer)+1;
    char *str = StrDuplicate(inStr.m_buffer);
    char *strOld = StrDuplicate(m_buffer);

    SafeArrayDelete(m_buffer);
    m_buffer = new char[len];
    strcpy(m_buffer,strOld);
    strcat(m_buffer,inStr.m_buffer);
    SafeArrayDelete(str);
    SafeArrayDelete(strOld);
}

Исправлено форматирование. Пожалуйста, не забывайте пользоваться тегами [c] ... [/c], [code] ... [/code] и т.п. для выделения фрагментов кода. -- ПК.
With best regards, roma_k.
Re: Моя первая реализация String
От: Нахлобуч Великобритания https://hglabhq.com
Дата: 08.07.04 11:29
Оценка:
Здравствуйте, roma_k, Вы писали:

_>Оцените пожалуйста, интересны все мои ошибки, особенно в реализации операторов !!!

_>// Заголовок
class nvString
{
public:
    // constructor
    nvString();

    // Construct a string from a char pointer
    nvString(const char* inStr);

    // Copy-constructor
    nvString(const nvString& inStr);

    // destructor
    virtual ~nvString();

    // Type cast to char pointer
    inline operator const char *() const
    { return m_buffer; }
    
    // Indexing operator
    inline char operator[](int i) const
    { return m_buffer[i]; }
    
    // Сделай еще что-нибудь типа "GetAt()" с проверкой индекса

    // Char pointer atribuition operator
    const nvString& operator=(const char* inStr);

    // Atribuition operator
    const nvString& operator=(const nvString& inStr);

    // Такие два оператора, имхо, лучше делать глобальными
    // Concatenation operator with a char pointer
    nvString operator+(const char* inStr);

    // Concatenation operator
    nvString operator+(const nvString& inStr);

    // Self-concatenation operator with a char pointer
    const nvString& operator+=(const char* inStr);
    
    // Self-concatenation operator
    const nvString& operator+=(const nvString& inStr);

    void Clear(void);
    
    // Find a sub-string in the string
    inline int Find(const char *str) const
    { 
        char *pos=strstr(m_buffer,str);
        if (pos == 0)
            return -1;
        return (int)(pos-m_buffer); 
    }

    // Find the first occurrence of a character in the string
    inline int Find(char c) const
    { 
        char *pos = strchr(m_buffer,c);
        if (pos == 0)
            return -1;
        return (int)(pos-m_buffer); 
    }

    // Find the last occurrence of a character in the string
    inline int FindLast(char c) const
    {
        char *pos = strrchr(m_buffer,c);
        if (pos == 0)
            return -1;
        return (int)(pos-m_buffer); 
    }

    // Change the 'i'-th character of the string
    // Удобнее было бы еще и через индексирование сделать. Через прокси-класс :)
    inline void SetChar(int i,char c)
    { 
        if (i < (int)strlen(m_buffer)) 
            m_buffer[i] = c;
    }

    // Crop the first 'n' characters of the string
    inline void CropBegin(int n)
    { 
        if (n < (int)strlen(m_buffer))
        {
            strcpy(m_buffer,&m_buffer[n]);
        }
    }
    
    // А сравнения с nvString?

    // equal compare operator    
    inline int operator==(const char *str) const 
    { return strcmp(m_buffer,str)==0; }

    inline int operator!=(const char *str) const 
    { return strcmp(m_buffer,str)!=0; }

    inline int operator>(const char *str) const 
    { return strcmp(m_buffer,str)>0; }

    inline int operator<(const char *str) const 
    { return strcmp(m_buffer,str)<0; }

    inline int operator>=(const char *str) const 
    { return strcmp(m_buffer,str)>=0; }

    inline int operator<=(const char *str) const 
    { return strcmp(m_buffer,str)<=0; }

    // Compare with a char pointer
    inline int Compare(const char *str) const
    { return strcmp(m_buffer,str); }

    // Compare the first 'n' characters of the string with a char pointer
    inline int Compare(const char *str,int n) const
    { return strncmp(m_buffer,str,n); }

    // Compare with a char pointer, case-insensitive flavour
    inline int CompareNoCase(const char *str) const
    { return stricmp(m_buffer,str); }

    // Change all characters to lower-case
    inline void ToLower()
    { strlwr(m_buffer); }

    // Change all characters to upper-case
    inline void ToUpper()
    { strupr(m_buffer); }

    // Return the length of the string in bytes
    // Это кэшировать надо
    inline int Length() const
    { return m_nLength; }

private:
    char *m_buffer;
    int m_nLength;
};
HgLab: Mercurial Server and Repository Management for Windows
Re: Моя первая реализация String
От: SergeMukhin Россия  
Дата: 08.07.04 11:30
Оценка:
Здравствуйте, roma_k, Вы писали:

_>Оцените пожалуйста, интересны все мои ошибки, особенно в реализации операторов !!!


1. чем этот String лучше других?
2. почему С текст не форматирован?
3. вместо int надо size_t (где речь идет о длинах)
4. почему StrDuplicate не в классе?
5. где поддержка UNICODE?
6. в += используется strcpy/strcat вместо memcpy*2
и вообще там получается ТРИ раза new, и пять копирований строк!!! не многовато ли?

и т.д. и т.п.

вообщем на троечку. базовые знания языка есть.
---
С уважением,
Сергей Мухин
Re: Моя первая реализация String
От: _AK_ Россия  
Дата: 08.07.04 11:47
Оценка:
Здравствуйте, roma_k, Вы писали:

_>Оцените пожалуйста, интересны все мои ошибки, особенно в реализации операторов !!!


Сходу найдено следующее. Если поискать чуть тщательней, то несомневаюсь что список можно расширить в два-три раза.

1) Лишние опреаторы (с учётом того что конструктор не-explicit).
2) Постоянное использование в качестве индекса типа int.
3) До глубины души умиляет SafeArrayDelete (явно внутри что-то типа: if (p) {delete p;})
4) exception-safety и не пахнет (new то может швынуть bad_alloc — не стоит забывать про это)
5) Класс позволяет писать следующие загадочные вещи:

nvString a,b,c;
a+b=c;


_>Моя первая реализация String


Лучше чтобы она была бы ещё и последней.
Re: Моя первая реализация String
От: denisku Россия  
Дата: 08.07.04 11:53
Оценка:
Здравствуйте, roma_k, Вы писали:

[...]

1) почему деструктор виртуальный? у тебя нет ни одного виртуального метода.
2) лучше хранить длину строки в отдельной переменной, а не вызывать каждый раз strlen(). Очень неэффективно получается..
3) оператор индексирования сделан так, что с помощью него не изменить содержимого строки. То есть написать что-то типа такого не получится:
my_str[0] = 'a';

ИМХО, не очень удобно. Я бы предложил такую реализацию:
// Indexing operator
inline char operator[](const size_t ind) const { 
 return m_buffer[i];
}

inline char& operator[](const size_t ind) { 
 return m_buffer[i];
}

4) предлагаю функцию StrDuplicate() сделать статической и private класса.
5) не нашел определения функции SafeArrayDelete()...
6) оператор+= реализован очень уж неэффективно.. каждый раз вызывается функция StrDuplicate() [и не раз вызывается], а он выделяет память через new... в общем, задумайся над этим куском кода
7) еще я бы добавил конструктор, который принимает 2 параметра: символ и длину строки. Чтобы вся строка состояла из этих символов.
8) operator+= должен возвращать ссылку на объект твоего класса(а не void!). У тебя нельзя записать так:
my_str2 = my_str1 += "aaaaa";

9) добавь operator+=(const char).
10) добавь operator+(const char).
11) добавь operator=(const char).
12) может память выделять немного заранее? то есть сначала выделяем какой-то кусок памяти, его используем. Если не хватает памяти для какой-то операции, выделяем новый кусок памяти(например, в 2 раза больше, чем старый), копируем туда содержимое и освобождаем память под старый буффер. хоть и памяти будет жрать больше, работать будет быстрее. так реализовано(по аналогии) в std::string.
3) удачи
Извините за потраченный траффик..
Re[2]: Моя первая реализация String
От: LIS  
Дата: 08.07.04 13:29
Оценка:
Здравствуйте, _AK_, Вы писали:

_AK>3) До глубины души умиляет SafeArrayDelete (явно внутри что-то типа: if (p) {delete p;})


А можно спросить — чем плохо использование такой конструкции?
Re[3]: Моя первая реализация String
От: _nn_  
Дата: 08.07.04 13:31
Оценка:
Здравствуйте, LIS, Вы писали:

LIS>Здравствуйте, _AK_, Вы писали:


_AK>>3) До глубины души умиляет SafeArrayDelete (явно внутри что-то типа: if (p) {delete p;})


LIS>А можно спросить — чем плохо использование такой конструкции?

Это не плохо, просто смысла в проверке никакого.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Моя первая реализация String
От: Lorenzo_LAMAS  
Дата: 08.07.04 13:36
Оценка: +3
_AK>
_AK>nvString a,b,c;
_AK>a+b=c;
_AK>


Предлагаю попробовать такое
std::string a, b, c;
a + c = b;


_>>Моя первая реализация String


_AK>Лучше чтобы она была бы ещё и последней.


Зачем так? Человек попросил указать ошибки, а ему — такие гадости.
Of course, the code must be complete enough to compile and link.
Re[4]: Моя первая реализация String
От: LIS  
Дата: 08.07.04 13:38
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Здравствуйте, LIS, Вы писали:


LIS>>Здравствуйте, _AK_, Вы писали:


_AK>>>3) До глубины души умиляет SafeArrayDelete (явно внутри что-то типа: if (p) {delete p;})


LIS>>А можно спросить — чем плохо использование такой конструкции?

__>Это не плохо, просто смысла в проверке никакого.

А как же проверить что объект был удален до этого?
Я вот делаю так:

#define DELETE_P if (p) { delete p; p = NULL; }


и потом когда еще раз пытаюсь удалить объект, то никаких exception не валится (хотя обработку все равно надо ставить).
Re[5]: Моя первая реализация String
От: SergeMukhin Россия  
Дата: 08.07.04 13:45
Оценка:
Здравствуйте, LIS, Вы писали:


LIS>
LIS>#define DELETE_P if (p) { delete p; p = NULL; }
LIS>


LIS>и потом когда еще раз пытаюсь удалить объект, то никаких exception не валится (хотя обработку все равно надо ставить).


достаточно {delete p; p = NULL;}

delete для NULL ничего не делает.
---
С уважением,
Сергей Мухин
Re[5]: Моя первая реализация String
От: _nn_  
Дата: 08.07.04 13:45
Оценка:
Здравствуйте, LIS, Вы писали:

LIS>Здравствуйте, _nn_, Вы писали:


__>>Здравствуйте, LIS, Вы писали:


LIS>>>Здравствуйте, _AK_, Вы писали:


_AK>>>>3) До глубины души умиляет SafeArrayDelete (явно внутри что-то типа: if (p) {delete p;})


LIS>>>А можно спросить — чем плохо использование такой конструкции?

__>>Это не плохо, просто смысла в проверке никакого.

LIS>А как же проверить что объект был удален до этого?

LIS>Я вот делаю так:

LIS>
LIS>#define DELETE_P if (p) { delete p; p = NULL; }
LIS>


Можно писать и так :
delete p;
p=NULL;


LIS>и потом когда еще раз пытаюсь удалить объект, то никаких exception не валится (хотя обработку все равно надо ставить).
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Моя первая реализация String
От: Вадим Никулин Россия Здесь
Дата: 08.07.04 14:02
Оценка:
Здравствуйте, roma_k, Вы писали:

_>Оцените пожалуйста, интересны все мои ошибки, особенно в реализации операторов !!!

_> // Type cast to char pointer
_> inline operator const char *() const
_> { return m_buffer; }

_> // Indexing operator

_> inline char operator[](int i) const
_> { return m_buffer[i]; }

Наличие двух таких операторов одновременно часто приводит компиляторы в тупик. Александреску
Автор(ы): Андрей Александреску

В книге изложена новая технология программирования, представляющая собой сплав обобщенного программирования, метапрограммирования шаблонов и объектно- ориентированного программирования на С++. Настраиваемые компоненты, созданные автором, высоко подняли уровень абстракции, наделив язык С++ чертами языка спецификации проектирования, сохранив всю его мощь и выразительность. В книге изложены способы реализации основных шаблонов проектирования. Разработанные компоненты воплощены в библиотеке Loki, которую можно загрузить с Web-страницы автора. Книга предназначена для опытных программистов на С++.
рекомендует избавиться от operator const char *. Он разбирает похожий пример, но для указателей.
Еще я не могу оценить смысл виртуальности деструктора.
Re[2]: Моя первая реализация String
От: Вадим Никулин Россия Здесь
Дата: 08.07.04 14:03
Оценка:
Здравствуйте, Нахлобуч, Вы писали:

Н>Здравствуйте, roma_k, Вы писали:


_>>Оцените пожалуйста, интересны все мои ошибки, особенно в реализации операторов !!!

_>>// Заголовок
Н>
Н>class nvString
Н>{
Н>public:

Н>    // Return the length of the string in bytes
Н>    // Это кэшировать надо
Н>    inline int Length() const
Н>    { return m_nLength; }

Н>private:
Н>    int m_nLength;            // Может mutable ?
Н>};
Н>
Re[2]: Моя первая реализация String
От: AndrewJD США  
Дата: 08.07.04 14:06
Оценка:
Здравствуйте, SergeMukhin, Вы писали:

SM>Здравствуйте, roma_k, Вы писали:


_>>Оцените пожалуйста, интересны все мои ошибки, особенно в реализации операторов !!!


SM>3. вместо int надо size_t (где речь идет о длинах)

Почему ?

SM>5. где поддержка UNICODE?

Должна быть?
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re[2]: Моя первая реализация String
От: Lorenzo_LAMAS  
Дата: 08.07.04 14:09
Оценка:
ВН>Наличие двух таких операторов одновременно часто приводит компиляторы в тупик.

Да, особенно если типа параметра у оператора [] не int, а std::size_t :

#include <cstddef>
class String
{
public:
   operator const char * ()const;
   char & operator[](std::size_t);
   char operator[](std::size_t)const;
};
///
String s;
///
char c = s[0];
Of course, the code must be complete enough to compile and link.
Re[3]: Моя первая реализация String
От: SergeMukhin Россия  
Дата: 08.07.04 14:10
Оценка: +1
Здравствуйте, AndrewJD, Вы писали:

AJD>Здравствуйте, SergeMukhin, Вы писали:


SM>>Здравствуйте, roma_k, Вы писали:


_>>>Оцените пожалуйста, интересны все мои ошибки, особенно в реализации операторов !!!


SM>>3. вместо int надо size_t (где речь идет о длинах)

AJD>Почему ?

например strlen выдает size_t, и так для переносимости.

SM>>5. где поддержка UNICODE?

AJD>Должна быть?

да, и класс должен быть шаблном.
---
С уважением,
Сергей Мухин
Re[3]: Моя первая реализация String
От: Нахлобуч Великобритания https://hglabhq.com
Дата: 08.07.04 14:22
Оценка:
Здравствуйте, Вадим Никулин, Вы писали:

ВН>Здравствуйте, Нахлобуч, Вы писали:


Н>>Здравствуйте, roma_k, Вы писали:


_>>>Оцените пожалуйста, интересны все мои ошибки, особенно в реализации операторов !!!

_>>>// Заголовок
Н>>
Н>>class nvString
Н>>{
Н>>public:

Н>>    // Return the length of the string in bytes
Н>>    // Это кэшировать надо
Н>>    inline int Length() const
Н>>    { return m_nLength; }

Н>>private:
Н>>    int m_nLength;            // Может mutable ?
Н>>};
Н>>


А смысл? Там же нет константных функций, которые чего-то с длиной делают.
HgLab: Mercurial Server and Repository Management for Windows
Re[6]: Моя первая реализация String
От: kaa_t Россия  
Дата: 08.07.04 14:24
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Можно писать и так :

__>
__>delete p;
__>p=NULL;
__>


При таком варианте приходится полагатся, на разработчиков компиляторов,а также на разработчиков библиотек.

LIS>>
LIS>>#define DELETE_P if (p) { delete p; p = NULL; }
LIS>>


Так надежней. Хотя и устарело...
Re[7]: Моя первая реализация String
От: SergeMukhin Россия  
Дата: 08.07.04 14:28
Оценка:
Здравствуйте, kaa_t, Вы писали:


__>>Можно писать и так :

__>>
__>>delete p;
__>>p=NULL;
__>>


_>При таком варианте приходится полагатся, на разработчиков компиляторов,а также на разработчиков библиотек.


ну вы даете!
1. причем тут компилятор?
2. неужели могут быть сомнения, что при реализации delete разработчики допустят такую ошибку?

_>Так надежней. Хотя и устарело...



что значит устарело? так вроде всегда было!
---
С уважением,
Сергей Мухин
Re[7]: Моя первая реализация String
От: _nn_  
Дата: 08.07.04 14:35
Оценка:
Здравствуйте, kaa_t, Вы писали:

_>Здравствуйте, _nn_, Вы писали:


__>>Можно писать и так :

__>>
__>>delete p;
__>>p=NULL;
__>>


_>При таком варианте приходится полагатся, на разработчиков компиляторов,а также на разработчиков библиотек.


LIS>>>
LIS>>>#define DELETE_P if (p) { delete p; p = NULL; }
LIS>>>


_>Так надежней. Хотя и устарело...

Что имеется вииду под словом "надежней" ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.