code

void 포인터를 삭제하는 것이 안전합니까?

codestyles 2020. 9. 11. 08:01
반응형

void 포인터를 삭제하는 것이 안전합니까?


다음 코드가 있다고 가정합니다.

void* my_alloc (size_t size)
{
   return new char [size];
}

void my_free (void* ptr)
{
   delete [] ptr;
}

안전한가요? 아니면 삭제 ptr하기 char*전에 캐스팅 해야 합니까?


그것은 "안전"에 달려 있습니다. 할당 자체에 대한 포인터와 함께 정보가 저장되기 때문에 일반적으로 작동하므로 할당 해제자가 올바른 위치로 반환 할 수 있습니다. 이러한 의미에서 할당자가 내부 경계 태그를 사용하는 한 "안전"합니다. (많은 사람들 이요)

그러나 다른 답변에서 언급했듯이 void 포인터를 삭제하면 소멸자가 호출되지 않아 문제가 될 수 있습니다. 그런 의미에서 "안전"하지 않습니다.

당신이하고있는 일을 당신이하고있는 방식대로 할 이유가 없습니다. 자체 할당 해제 함수를 작성하려면 함수 템플릿을 사용하여 올바른 유형의 함수를 생성 할 수 있습니다. 이를 수행하는 좋은 이유는 특정 유형에 대해 매우 효율적일 수있는 풀 할당자를 생성하는 것입니다.

다른 답변에서 언급했듯이 이것은 C ++에서 정의되지 않은 동작 입니다. 일반적으로 주제 자체가 복잡하고 상반되는 의견으로 가득 차 있지만 정의되지 않은 동작을 피하는 것이 좋습니다.


void 포인터를 통한 삭제는 C ++ 표준에 정의되어 있지 않습니다-섹션 5.3.5 / 3 참조 :

첫 번째 대안 (객체 삭제)에서 피연산자의 정적 유형이 동적 유형과 다른 경우 정적 유형은 피연산자의 동적 유형의 기본 클래스이고 정적 유형에는 가상 소멸자가 있거나 동작이 정의되지 않습니다. . 두 번째 대안 (배열 삭제)에서는 삭제할 객체의 동적 유형이 정적 유형과 다른 경우 동작이 정의되지 않습니다.

그리고 각주 :

이것은 void * 유형의 개체가 없기 때문에 void * 유형의 포인터를 사용하여 개체를 삭제할 수 없음을 의미합니다.

.


그것은 좋은 생각이 아니며 C ++에서 할 일이 아닙니다. 이유없이 유형 정보를 잃어 버리고 있습니다.

소멸자는 원시 유형이 아닌 유형에 대해 호출 할 때 삭제중인 배열의 객체에 대해 호출되지 않습니다.

대신 new / delete를 재정의해야합니다.

void *를 삭제하면 우연히 올바르게 메모리가 해제되지만 결과가 정의되지 않았기 때문에 잘못된 것입니다.

나에게 알려지지 않은 이유로 포인터를 void *에 저장하고 해제해야한다면 malloc과 free를 사용해야합니다.


void 포인터를 삭제하는 것은 실제로 가리키는 값에서 소멸자가 호출되지 않기 때문에 위험합니다. 이로 인해 애플리케이션에서 메모리 / 리소스 누수가 발생할 수 있습니다.


질문은 말이되지 않습니다. 당신의 혼란은 부분적으로 사람들이 자주 사용하는 엉성한 언어 때문일 수 있습니다 delete.

동적으로 할당 된 개체delete 를 삭제하는 데 사용 합니다 . 이렇게하면 해당 객체에 대한 포인터를 사용하여 삭제 표현식 을 형성 합니다 . "포인터를 삭제"하지 않습니다. 당신이 정말로하는 일은 "주소로 식별되는 객체를 삭제"하는 것입니다.

이제 왜 그 질문이 말이되지 않는지 알 수 있습니다. void 포인터는 "객체의 주소"가 아닙니다. 의미가없는 주소 일뿐입니다. 는 실제 개체의 주소에서왔다,하지만이로 인코딩했기 때문에 정보가 손실 유형 원래의 포인터. 객체 포인터를 복원하는 유일한 방법은 void 포인터를 객체 포인터로 다시 캐스팅하는 것입니다 (포인터가 의미하는 바를 작성자가 알아야 함). void그 자체는 불완전한 유형이므로 객체의 유형이 아니므로 void 포인터를 사용하여 객체를 식별 할 수 없습니다. (객체는 유형과 주소로 공동으로 식별됩니다.)


char에는 특별한 소멸자 논리가 없기 때문입니다. 이것은 작동하지 않습니다.

class foo
{
   ~foo() { printf("huzza"); }
}

main()
{
   foo * myFoo = new foo();
   delete ((void*)foo);
}

감독은 전화를받지 않습니다.


If you want to use void*, why don't you use just malloc/free? new/delete is more than just memory managing. Basically, new/delete calls a constructor/destructor and there are more things going on. If you just use built-in types (like char*) and delete them through void*, it would work but still it's not recommended. The bottom line is use malloc/free if you want to use void*. Otherwise, you can use template functions for your convenience.

template<typename T>
T* my_alloc (size_t size)
{
   return new T [size];
}

template<typename T>
void my_free (T* ptr)
{
   delete [] ptr;
}

int main(void)
{
    char* pChar = my_alloc<char>(10);
    my_free(pChar);
}

If you really must do this, why not cut out the middle man (the new and delete operators) and call the global operator new and operator delete directly? (Of course, if you're trying to instrument the new and delete operators, you actually ought to reimplement operator new and operator delete.)

void* my_alloc (size_t size)
{
   return ::operator new(size);
}

void my_free (void* ptr)
{
   ::operator delete(ptr);
}

Note that unlike malloc(), operator new throws std::bad_alloc on failure (or calls the new_handler if one is registered).


A lot of people have already commented saying that no, it's not safe to delete a void pointer. I agree with that, but I also wanted to add that if you're working with void pointers in order to allocate contiguous arrays or something similar, that you can do this with new so that you'll be able to use delete safely (with, ahem, a little of extra work). This is done by allocating a void pointer to the memory region (called an 'arena') and then supplying the pointer to the arena to new. See this section in the C++ FAQ. This is a common approach to implementing memory pools in C++.


There is hardly a reason to do this.

First of all, if you don't know the type of the data, and all you know is that it's void*, then you really should just be treating that data as a typeless blob of binary data (unsigned char*), and use malloc/free to deal with it. This is required sometimes for things like waveform data and the like, where you need to pass around void* pointers to C apis. That's fine.

If you do know the type of the data (ie it has a ctor/dtor), but for some reason you ended up with a void* pointer (for whatever reason you have) then you really should cast it back to the type you know it to be, and call delete on it.


I have used void*, (aka unknown types) in my framework for while in code reflection and other feats of ambiguity, and so far, I have had no troubles (memory leak, access violations, etc.) from any compilers. Only warnings due to the operation being non-standard.

It perfectly makes sense to delete an unknown (void*). Just make sure the pointer follows these guidelines, or it may stop making sense:

1) The unknown pointer must not point to a type that has a trivial deconstructor, and so when casted as an unknown pointer it should NEVER BE DELETED. Only delete the unknown pointer AFTER casting it back into the ORIGINAL type.

2) Is the instance being referenced as an unknown pointer in stack bound or heap bound memory? If the unknown pointer references an instance on the stack, then it should NEVER BE DELETED!

3) Are you 100% positive the unknown pointer is a valid memory region? No, then it should NEVER BE DELTED!

In all, there is very little direct work that can be done using an unknown (void*) pointer type. However, indirectly, the void* is a great asset for C++ developers to rely on when data ambiguity is required.


If you just want a buffer, use malloc/free. If you must use new/delete, consider a trivial wrapper class:

template<int size_ > struct size_buffer { 
  char data_[ size_]; 
  operator void*() { return (void*)&data_; }
};

typedef sized_buffer<100> OpaqueBuffer; // logical description of your sized buffer

OpaqueBuffer* ptr = new OpaqueBuffer();

delete ptr;

For the particular case of char.

char is an intrinsic type that does not have a special destructor. So the leaks arguments is a moot one.

sizeof(char) is usually one so there is no alignment argument either. In the case of rare platform where the sizeof(char) is not one, they allocate memory aligned enough for their char. So the alignment argument is also a moot one.

malloc/free would be faster on this case. But you forfeit std::bad_alloc and have to check the result of malloc. Calling the global new and delete operators might be better as it bypass the middle man.

참고URL : https://stackoverflow.com/questions/941832/is-it-safe-to-delete-a-void-pointer

반응형