在编写响应时,我编写了一些代码,这些代码挑战了我对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?
}
我的问题是,如何将用户访问权限传递给指针(因此他们可以像使用char数组一样使用它),同时使删除功能无法删除它,最好是抛出某种抱怨或异常?
答案 0 :(得分:6)
如果您的用户使用的是delete[]
指针,但他们没有从new[]
获得指针,请使用线索将其击中头部。
指针可以解除引用的原因有很多,但不能传递给删除:
malloc
或其他非new
分配器。其中一些将在运行时在异常中显示。其他人稍后会导致崩溃。根据标准,所有都是“未定义的行为”。
假设指针不能用作delete
的参数,除非另有明确说明。
如果入门级程序员犯了这个错误,请教育他们。如果“经验丰富”的开发人员正在这样做,请将他们放在简历上解雇。
如果你只是想让它受到伤害,请分配一个大于必要的数组return Array + 1;
。如果他们试图使用delete[]
,现在一切都会爆炸。
实际应用是,(更多)可能会使程序在伪造的删除调用中崩溃,而违规函数仍然在调用堆栈上。原来可能会继续运行一段时间,最后崩溃无辜的代码。所以这有助于你抓住愚蠢的用户。
答案 1 :(得分:5)
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>
,除非你有强的理由不才能使用它。
答案 2 :(得分:1)
你的const没有效果,你返回一个const指针,而不是指向const char的指针,这就是你想要的。另请参阅Nawaz关于使用向量的建议。
答案 3 :(得分:1)
你真正做的最多的事情就是返回delete
不可接受的操作数。这可以是一个RAII对象(比如std :: vector或std :: array),也可以是一个引用(根据你的情况,可能是合适的)。
[Un]幸运的是,C ++让程序员可以做各种偷偷摸摸的事情。
答案 4 :(得分:0)
你不能完全阻止愚蠢,但你可以通过使用访问机制而不是返回实际的数组指针来扼杀它。
char& operator[](size_t index) { return Array[index]; }
这并不能解决像char数组那样对待它的能力,但正如已经指出的那样,如果你发现那个指针,(坏)程序员可以随意对它进行删除。