如何使用户无法删除动态数组呢?

SSi*_*ht3 2 c++ pointers dynamic-allocation

在编写响应时,我编写了一些代码来挑战我对const指针如何工作的假设.我假设删除函数无法删除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?
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,如何将用户访问权限传递给指针(因此他们可以像char数组一样使用它),同时使删除功能无法删除它,最好是抛出某种抱怨或异常?

Ben*_*igt 6

如果你的用户正在使用delete[]他们没有得到的指针new[],用一个线索棒击中他们的头部.

指针可以解除引用的原因有很多,但不能传递给删除:

  • 别人会删除它.
  • 这不是块的开始.
  • 它来自malloc或其他一些非new分配器.
  • 它具有静态而非动态的寿命.
  • 如果有自动寿命.

其中一些将在运行时在异常中显示.其他人稍后会导致崩溃.根据标准,所有都是"未定义的行为".

delete除非另有明确说明,否则应该假设指针不能用作参数.

如果入门级程序员犯了这个错误,请教育他们.如果"经验丰富"的开发人员正在这样做,请将他们放在简历上解雇.


如果你只是想让它在他们这样做时受到伤害,那么将数组分配给一个大于必要的数组,并且return Array + 1;.如果他们试图使用,现在一切都会爆炸delete[].

实际使用是,它(更多)可能会使程序在伪造的删除调用中崩溃,而违规函数仍然在调用堆栈上.原来可能会继续运行一段时间,最后崩溃无辜的代码.所以这有助于你抓住愚蠢的用户.

  • @ SSight3:你仍然可以只删除[](Test.GetArray() - 1);`如果用户看到你的内部指针.他也可以编辑你的实现.不要忽视这一点,只做最简单,最快速的事情. (2认同)

Naw*_*waz 5

delete [] Temp.GetArray(); //This works?! How do I prevent this?
Run Code Online (Sandbox Code Playgroud)

只要它返回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
Run Code Online (Sandbox Code Playgroud)

但是,如果你改变这个:

char *Array;
Run Code Online (Sandbox Code Playgroud)

对此

std::vector<char> Array;
Run Code Online (Sandbox Code Playgroud)

然后你可以通过返回它来实现你想要的东西:

std::vector<char> & GetArray() { return Array; }
Run Code Online (Sandbox Code Playgroud)

底线是 :

在C++中,动态数组的默认选择应该是std::vector<T>,除非你已经非常强大的理由使用它.

  • @ SSight3这样的用户也可以写`int i = 7; 删除&i;`并鼓掌自己调用UB,无论其他什么可能获得他. (3认同)
  • @ SSight3:`delete [] Test.data();` - 好吧,你可以像你想的那样偏执狂,但当用户这样做时,这是他自己的错,你无能为力.一个更好的选择是不返回数组(或向量)并简单地用适当的`operator []`包装访问,但即使这样,用户也可以做诸如`delete []&Temp [0];`之类的愚蠢的东西.你可以从`operator []`返回一个代理,它会重载`operator&'或类似的东西,但最重要的是,你不能阻止你的用户在脚下射击.你唯一能做的就是让它们更难. (2认同)