C ++ Начинающий Удалить код

Я пытаюсь динамически выделить память в куче, а затем удалить выделенную память. Ниже приведен код, который доставляет мне трудности:

// String.cpp
#include "String.h"

String::String() {}

String::String(char* source)
{
 this->Size = this->GetSize(source);
 this->CharArray = new char[this->Size + 1];
 int i = 0;
 for (; i < this->Size; i++) this->CharArray[i] = source[i];
     this->CharArray[i] = '\0';
}

int String::GetSize(const char * source)
{
 int i = 0;
        for (; source[i] != '\0'; i++);
        return i;
}

String::~String()
{
 delete[] this->CharArray;
}

Вот ошибка, которую я получаю, когда компилятор пытается удалить CharArray:

0xC0000005: место чтения нарушения прав доступа 0xccccccc0.

И вот последний вызов в стеке:

msvcr100d.dll! operator delete (void * pUserData) Строка 52 + 0x3 байта C ++

Я почти уверен, что ошибка существует в этом фрагменте кода, но предоставлю вам любую другую необходимую информацию. Ах да, используя VS 2010 для XP.

Изменить: вот мой String.h

// String.h - string class
#pragma once

#define NOT_FOUND -1

class String
{
public:
    String();
    String(char* source);
    static int GetSize(const char * source);
    int Find(const char* aChar, int startPosition = 0);
    ~String();
private:
    char* CharArray;
    int Size;
};

person Pooch    schedule 28.04.2010    source источник
comment
Какое значение будет у CharArray, когда вы закончите построение по умолчанию?   -  person GManNickG    schedule 28.04.2010
comment
Можете ли вы опубликовать код, где вы это используете? Я подозреваю, что у вас может быть код, использующий конструктор по умолчанию, который оставляет CharArray неинициализированным.   -  person kibibu    schedule 28.04.2010
comment
Почему этот ›член, если можно сказать просто член?   -  person tiftik    schedule 28.04.2010
comment
У меня есть другие классы, которые используют мой собственный класс String. Например, у меня есть: Email :: Email (const String & email) Кроме этого, я создаю только строку со значением, например: String temp (buffer);   -  person Pooch    schedule 28.04.2010
comment
Можете ли вы также опубликовать свой h-файл. Мне интересно узнать о типе charArray.   -  person Michael Dorgan    schedule 28.04.2010
comment
Должен ли я установить в моем конструкторе по умолчанию какое-то значение по умолчанию для CharArray и Size? Должен ли я иметь условие, которое проверяет, назначен ли CharArray указателю, прежде чем пытаться удалить его в моем деструкторе?   -  person Pooch    schedule 28.04.2010
comment
@Pooch: Да, это то, что делают конструкторы по умолчанию, и нет, на самом деле. Установите их на 0, и удаление 0 нормально (это ничего не делает. Технически это ваш чек).   -  person GManNickG    schedule 28.04.2010
comment
@rlbond: да, я это понял и сразу удалил свой комментарий. Я надеялся, что за эти 20 секунд никто не ответит: D. Тем не менее, спасибо.   -  person mingos    schedule 28.04.2010
comment
@mingos: Не беспокойтесь об этом;)   -  person rlbond    schedule 28.04.2010


Ответы (4)


Измените ваш ctor по умолчанию; учитывая получаемую вами ошибку, вызов удаления пытается удалить указатель, который никогда не был инициализирован.

String::String() : Size(0), CharArray(NULL) {}

Также остерегайтесь «конструктора копирования». Вы можете сделать его закрытым, чтобы убедиться, что вы не запускаете его неявно. (Его не нужно реализовывать, если вы не собираетесь его вызывать, просто вставьте прототип функции в определение вашего класса.) Можно аналогичным образом «отключить» оператор присваивания.

class String
{
   // other stuff

private:
    String(String&);
    String& operator=(String&);
};

Это дополнение соответствует «Правилу трех», которое гласит, что если какому-либо классу нужен деструктор, конструктор копирования или оператор присваивания, ему, вероятно, понадобятся все три.

Изменить: см. http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29

person dash-tom-bang    schedule 28.04.2010
comment
Спасибо за информацию! Я попробую это вместе с приведенным выше советом и сообщу вам, ребята, если это решит мою проблему. - person Pooch; 28.04.2010
comment
Ваш коллективный совет по инициализации членов в конструкторе решил мою первоначальную проблему. Затем я получал еще одну ошибку, которая была результатом неправильной реализации оператора '='. Ха! Угадайте, что Правило трех существует не просто так. Еще раз спасибо всем за помощь! - person Pooch; 28.04.2010
comment
LOL, действительно, правило трех многое мне объяснило, прежде чем я действительно его принял. :) - person dash-tom-bang; 28.04.2010

String::String(): CharArray( 0 ) {}

Вы не инициализируете CharArray в каждом конструкторе, поэтому в некоторых случаях вы удаляете неинициализированный указатель.

person Peter Kovacs    schedule 28.04.2010

У вас есть несколько конструкторов, но только один из них вызывает new. Ваш деструктор всегда вызывает удаление, так что это ваша ошибка.

person Michael Dorgan    schedule 28.04.2010

Я думаю, что @ dash-tom-bang правильный. Вы, вероятно, копируете String, а затем дважды удаляете его данные. Однако я сохраню здесь свои старые ответы для справки.

Вам нужно будет опубликовать код, который использует String, но я могу заметить здесь несколько проблем:

  1. Что, если source в конструкторе имеет значение NULL? Сразу возникает исключение нулевого указателя. Что еще хуже, если вы получите это исключение, деструктор попытается удалить память, которая никогда не была выделена. Это может вызвать описанную выше ошибку, если вы используете _4 _..._ 5_.

  2. GetSize не должен быть функцией-членом String, потому что он не использует никаких переменных-членов. По крайней мере, это должно быть static.

person rlbond    schedule 28.04.2010
comment
… Другими словами, можно с уверенностью предположить, что никто не передаст вам указатель NULL, если вы не скажете, что они могут. Кроме того, по умолчанию рабочие исключения, такие как доступ NULL, не вызывают исключений C ++; они вызывают немедленное прекращение. - person Potatoswatter; 28.04.2010