好吧,在你有一个带有指针参数并返回指针的函数之前,我已经看到过这种情况。
但是你可以选择不传递一个参数,它会返回一个动态分配的指针,但如果你传递一个指针,那么它只是填充它而不是在堆上创建一个。这是一个没有重载的单一功能。
我的问题是这是如何安全地完成的?
我猜这是这样的:
point* funct(point *p = some_value)
{
if p == some_value
//create a point *p on the heap
else
//create use the given *p and fill it in
return p
}
现在我想不出这是否是正确的方法,如果它是什么可能是一个好的some_value?它不能为NULL,因为当你传递空指针时它也会是NULL并且不确定它是否可以安全地使它大于0.你也不能在指针上有负数,所以什么是安全值?
有什么好方法可以跨平台进行PORTABLE吗?
编辑:
好吧也许我没有正确解释基本上我想要这样使用的功能:
point *x;
point *y;
x = func();
func(y);
不
x = func(NULL);
如果我使用NULL,只有当我执行func(y);
时才会出现错误分段错误原因是:
用户传递他管理的指针,例如在堆栈上创建的指针,或者如果没有给出,则函数将返回动态指针。我不想强制只返回动态内存或仅接受指向填充的内容。
我知道我以前见过这件事。
答案 0 :(得分:8)
正常的解决方案是'if NULL allocate' - 这就是'c'realloc的作用。
看起来你想拥有一个使用现有内存的函数(如果提供),或者分配它自己的内存。
如果传递有效指针,则不清楚应该返回什么
它应该返回指针吗?
或者它应该为null以确保没有两个指向同一位内存的指针副本 - 如果它们被释放将导致问题。
将**指针传递给函数并需要参数可能更安全 - 即使该争论是指向null的指针。
答案 1 :(得分:3)
很明显,如果有人打电话给函数(NULL),那么无论如何都会导致崩溃。那么为什么不让some_value = NULL来制作
if(p==NULL){
p=dynamic_memory;
}
其中dynamic_memory在构造函数中分配(不是线程安全的!)或者通过调用new
替换dynamic_memory编辑:
或者。如果你的函数中必须有3个状态,一个如果没有提供参数,一个用于传递有效指针,一个用于传递NULL,那么你可以使用指向指针。
像
void *func(void** p=NULL){
if(p==NULL) ...//user supplied no argument
if(*p==NULL) ...//user supplied NULL
else //user supplied valid pointer
这似乎不是你想要的,然后人们将不得不通过'&'传递指针你的函数..(&NULL
甚至有效吗?)
答案 2 :(得分:3)
我的猜测更多的是:
point* funct(point *p = NULL)
{
if (p == NULL) {
// create a point *p on the heap
// and use it
return(p);
}
else {
//use the given *p and fill it in
return(NULL);
}
}
不太确定是否有可能指向你的点对象传入。可能很难检查,并检查传入的对象的类型,即使用RTTI“查看封面”,并不是最好的面向对象实践。
答案 3 :(得分:2)
类似的东西:
T* func(T* p) {
if(!p) {
p = new T;
}
// do whatever with p
return p;
}
然后你可以这样做:
T* x = func(NULL);
// whatever
delete x;
或:
T x;
func(&x);
修改强>
有几个库使用的非线程安全选项。基本上它的工作原理如下:
T* func(T* p) {
static T buf;
if(!p) {
p = buf;
}
// do whatever with p
return p;
}
然后你可以这样做:
T* p = func(NULL);
或:
T x;
T* p = func(&x);
这些版本通常还有“可重入”版本,它们通常与非线程安全版本相关联:
T* func(T* p) {
// behaves as above example, except now we can
// use func_r in a thread safe way if we need to
static T buf;
return func_r(p, buf);
}
T* func_r(T* p, T *buf) {
if(!p) {
p = buf;
}
// do whatever with p
return p;
}
答案 4 :(得分:2)
调用func(y)时出错,因为y未初始化。它包含指向内存中随机位置的随机位。您需要将y初始化为NULL。
point *x, *y;
x = func();
y = NULL;
y = func(y); // so it can be deleted later you need to assign the return value
delete x;
delete y;
为什么不这样做?并完全避免堆分配。
point x, y;
func(&x);
func(&y);
或者:
point *x;
point *y = new point();
x = func();
func(y);
delete x;
delete y;
正如我在上面的评论中所说,内存所有权在您的功能中令人困惑。动态分配其结果的函数应该每次或不执行任何操作。当他们在某些时候这样做时,内存泄漏的可能性要高得多。
就个人而言,我会更进一步,避免所有分配,通过引用传递:
void func(point& p)
{
//do stuff
}
point x, y;
func(x);
func(y);
答案 5 :(得分:1)
如果要分配,则应传递NULL(默认值为null),如果要填写则传递空指针。
正如jeffamaphone评论的那样,空指针和NULL之间存在差异,使用条件语句检查它是否为空指针或NULL
答案 6 :(得分:1)
使用NULL有什么问题?这是处理这个问题的一般方法。如果确实需要区分“调用者没有通过”和“调用者传递NULL”,那么在32位系统上使用0xFFFFFFFF
或在64位上使用0xFFFFFFFFFFFFFFFF
系统
point * funct(point * p = (point *)(-1))
{
if (p == (point *)(-1))
{
p = new point();
}
if (p == NULL)
{
// special case handling
return NULL;
}
// fill in p
return p
}
只要你在二元赞美架构上,' - 1'演员将始终是最大指针值。如果您愿意,可以随意使用重新演绎的演员来代替C风格演员。
答案 7 :(得分:1)
但是你可以选择不传递一个参数,它会返回一个动态分配的指针,但如果你传递一个指针,那么它只是填充它而不是在堆上创建一个。这是一个没有重载的单一功能。
您可以重载函数,而不是使用默认参数:
point* funct(point *p = some_value)
{
// fills p
}
point* funct()
{
return funct(new point());
}
它可能不是正确的方法,但在某些地方我认为在linux库中有一个功能与上面完全一样,不确定它是如何在内部分配的
我不知道有任何这样的功能。我猜你会想到realloc接受指针和size_t
,然后决定是分配内存,调整已分配的内存还是释放内存。
现在我想不出这是否是正确的方法,如果它是什么可能是一个好的some_value?它不能为NULL,因为当你传递空指针时它也会是NULL并且不确定它是否可以安全地使它大于0.你也不能在指针上有负数,所以什么是安全值?
我认为你的困惑来自对NULL
指针的基本误解。
观察:
int x = 5;
int* px = &x;
int* p_null = NULL;
int* p;
int* p_new = new int();
px
指向x,因此它不是NULL
。 p_null
以NULL
开头,这意味着它没有任何意义。
我认为您使用术语“空指针”来引用p
或p_new
之类的内容。但是,尽管p
未指向有效对象,但它也未设置为NULL
。它实际上是一个无效的指针,并且没有可移植的方式来判断它是无效的(在某些机器上它是may be possible to tell if something is obviously not valid,但即便如此,它也无法捕获所有无效指针 - 参见注释 - 和you probably don't want to anyway - 下半场。)
p_new
指向动态内存中的有效地址。它不是NULL。它不是空的。实际上,new
会将int
初始化为0。
换句话说,NULL
是您传递给函数的值,这些函数期望指针告诉它们您没有指针。就是这样。并没有真正的空指针的想法。悬空指针(未初始化的指针或指向您无权访问的内存的指针)不是NULL
,因为如果它们是NULL
则不会悬挂。并且在所有情况下都无法验证指针以确定它们是否有效。
注意强>
考虑:
int* p_new2 = new int();
delete p_new2;
delete
未将p_new2
设置为NULL
。所以在delete
之后,p_new2
将在有效指针的正确范围内有一个地址(意味着Windows的VirtualQuery方法会说“确定,指针可以指向那里”),但不会允许实际取消引用该内存地址。
注2
这是一个非常糟糕的主意,不要这样做:
int* funct()
{
int y = 5;
return &y;
}
int* x = funct();
y
返回后 funct()
不再存在。所以指向y
的{{1}}指针指向不存在的东西。所以你得到一个悬垂的指针。你不是在谈论这样做,但这是一个常见的错误,它会咬你。
答案 8 :(得分:1)
你必须问自己为什么传递NULL我们给你一个seg-fault。当然不是因为NULL不是一个合适的值,它将由你的代码在传递NULL时所做的任何事情引起。但是,您选择不显示该代码。
您是否在调试器中完成了此代码?
除此之外,在C ++ 中不使用NULL。这是一个宏,并且对不正确的重新定义持开放态度。使用普通零(0)。语言放置保证转换为指针时的零文字常量不是有效地址。很可能你的NULL宏实际上被定义为零。
如果您尝试取消引用空指针,则会出现错误。
答案 9 :(得分:0)
默认值是它的默认值。这里没有 not 传递值这样的东西。它可能只发生在可变参数计数上,但这是不同的故事。
什么是“空指针”?
答案 10 :(得分:0)
你在找这个:
point* funct(point *p = some_value)
{
if (p == NULL)
return NULL;
if (p == some_value)
p = new point;
return p;
}
答案 11 :(得分:0)
好吧我已经决定不使用那个习惯看起来很糟糕虽然我知道其中一个unix或linux系统库有这样的功能。
我没有回答我自己的问题,但我只记得ctime成语,这可能是一种更安全的方式来做我想要的。我在谈论time()函数。
指针或按值返回对象的位置。
我认为它甚至可以提供更好的灵活性,通过用户控制的指针返回值,堆或堆栈分配。我不知道为什么我之前没想过这个。
你们有什么事,ctime成语好多了吧?
编辑:那个成语是否使用NULL检查?
答案 12 :(得分:0)
如果您真的希望以这种方式拆分它们,您不会意外地提供默认功能,那么您应该使功能过载。
point* funct() {
//alocate a point* p here
return funct(p);
}
和
point* funct(point *p) {
//do stuff
}