Как сделать так, чтобы пользователь не мог удалить динамический массив? - PullRequest
2 голосов
/ 10 октября 2011

При написании ответа я написал некоторый код, который оспаривал мои предположения о том, как работают константные указатели. Я предполагал, что указатели const не могут быть удалены с помощью функции удаления, но, как вы увидите из приведенного ниже кода, это не так:

#include <new>
#include <string.h>

class TestA
{
    private:
        char *Array;
    public:
        TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
        ~TestA(){if(Array != NULL){ delete [] Array;} }

        char * const GetArray(){ return Array; }
};

int main()
{
    TestA Temp;
    printf("%s\n",Temp.GetArray());
    Temp.GetArray()[0] = ' '; //You can still modify the chars in the array, user has access
    Temp.GetArray()[1] = ' '; 
    printf("%s\n",Temp.GetArray());
    //Temp.GetArray() = NULL //This doesn't work

    delete [] Temp.GetArray(); //This works?! How do I prevent this?
}

Мой вопрос: как передать пользователю доступ к указателю (чтобы они могли использовать его как массив символов), в то же время сделав так, чтобы функция удаления не могла его удалить, предпочтительно выдавая какую-то жалобу или исключение

Ответы [ 5 ]

6 голосов
/ 10 октября 2011

Если ваши пользователи используют delete[] на указателях, которые они не получили от new[], ударьте их по голове ударной битой.

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

  • Кто-то еще удалит его.
  • Это не начало блока.
  • Он был получен от malloc или другого не new распределителя.
  • Имеет статическое, а не динамическое время жизни.
  • Если имеет автоматическое время жизни.

Некоторые из них будут проявляться в исключениях во время выполнения. Другие вызовут сбои в более позднее время. Все это «неопределенное поведение» согласно стандарту.

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

Если программисты начального уровня делают эту ошибку, обучите их. Если «опытные» разработчики делают это, увольняйте их за то, что они лежали в их резюме.


Если вы просто хотите, чтобы это причиняло боль, когда они это делают, выделите массив на один больше, чем необходимо, и return Array + 1;. Теперь все взорвется, если они попытаются использовать delete[].

Практическое использование состоит в том, что (с большей вероятностью) это приведет к аварийному завершению программы внутри поддельного вызова для удаления, при этом функция-нарушитель все еще будет находиться в стеке вызовов. Где оригинал, вероятно, продолжит работать некоторое время, и, наконец, вылетает в невинном коде. Так что это поможет вам поймать глупых пользователей.

5 голосов
/ 10 октября 2011
delete [] Temp.GetArray(); //This works?! How do I prevent this?

Пока он возвращает char* или какой-либо другой указатель типа, вы не можете предотвратить это;не имеет значения, является ли выражение в операторе delete const, потому что все перечисленные ниже значения полностью допустимы в C ++:

char *pc = f(); 
delete [] pc;  //ok

const char *pc = g(); 
delete [] pc; //ok

char * const pc = h(); 
delete [] pc; //ok

const char * const pc = k(); 
delete [] pc; //ok

Однако, если вы измените это:

char *Array;

к этому

std::vector<char> Array;

И тогда вы можете достичь того, что вы хотите, вернув его как:

std::vector<char> & GetArray() { return Array; }

Суть:

В C ++выбор по умолчанию для динамического массива должен быть std::vector<T>, если только у вас нет очень сильных причин , а не для его использования.

1 голос
/ 10 октября 2011

Самое большее, что вы можете сделать, это вернуть что-то, что не является приемлемым операндом для delete.Это может быть объект RAII (например, std :: vector или std :: array), или это может быть ссылка (в зависимости от вашей ситуации, может быть подходящей).

[Un], к счастью, C ++ позволяетпрограммист делает всякие подлые вещи.

1 голос
/ 10 октября 2011

Ваше const не дает никакого эффекта, вы возвращаете указатель const, а не указатель на const char, что вам и нужно.Также см. Рекомендацию Nawaz об использовании векторов.

0 голосов
/ 10 октября 2011

Вы не можете полностью заблокировать глупость, но вы можете подавить ее немного, используя механизм доступа вместо возврата фактического указателя массива.

char& operator[](size_t index) { return Array[index]; }

Это не относится к возможности обращаться с ней как с символоммассив, но, как уже указывалось, если вы обнаружите этот указатель, (плохие) программисты могут свободно удалять на нем все, что хотят.

...