함수에 대한 포인터를 새로 할당하는 것이 합법적입니까?


33

함수에 대한 포인터는 void * 포인터에 저장할 수 없으므로 일반 데이터 포인터가 아닙니다. 그럼에도 불구하고 아래 코드와 같이 함수 포인터의 사본을 동적 메모리 (gcc 및 clang)에 저장할 수있는 것 같습니다. 이러한 코드는 C ++ 표준에 따라 합법적입니까, 아니면 일종의 컴파일러 확장입니까?

또한 함수 포인터에 대한 결과 포인터는 일반 데이터 포인터처럼 작동합니다. void *에 저장하고 static_cast에 의해 void *에서 검색 할 수 있습니다. 이 행동은 표준에 의해 보장됩니까?

int main()
{
  extern void fcn();
  void (*fcnPtr)() = &fcn;
  void (**ptrToFcnPtr)() = nullptr;

  //Make the copy of fcnPtr on the heap:
  ptrToFcnPtr = new decltype(fcnPtr)(fcnPtr);
  //Call the pointed-to function : 
  (**ptrToFcnPtr)();

  //Save the pointer in void* :
  void *ptr = ptrToFcnPtr;
  //retrieve the original ptr: 
  auto myPtr = static_cast< void(**)() > (ptr) ; 
  //free memory:
  delete ptrToFcnPtr ;

}

2
원시 funciton 포인터를 사용하지 마십시오. std::function대신 사용하십시오 .
일부 프로그래머 친구

new에 캐스팅 할 필요가 없습니다 void*. 함수가 void* ptr = &fcnPtr;아니라 fcnPtr객체 이기 때문에 마찬가지로 작동 합니다.
호두

5
@Someprogrammerdude std::function는 함수 포인터의 대체물이 아닌 임의의 호출 가능 파일을 저장하는 유형 소거 컨테이너입니다.
Michael Kenzel

7
(@Someprogrammerdude) 맹목적으로 사용 / 권장하지 마십시오 std::function. "다형성 (polymorphic)"함수 (즉, 일부 람다의 경우와 같이 상태를 포함하더라도 올바른 서명을 가진 것)를 저장하는 기능에는 훌륭하지만, 필요하지 않은 오버 헤드도 추가합니다. 함수에 대한 포인터는 POD입니다. A std::function는 아닙니다.
매튜

2
@Matthew 공정하게, Adrian은 동적으로 포인터를 기능에 할당하고 유형을 지우는 것에 대해 질문하고 있으므로이 void*질문의 맥락에서 std::function정확히 그들이 찾던 것 같습니다. SPD의 일반적인 함수 포인터 해제가 적절하지 않다는 데 동의합니다.
eerorika

답변:


27

함수 포인터는 객체 포인터가 아니지만 "일부 유형의 함수에 대한 포인터"는 여전히 객체 유형 [basic.types] / 8 입니다. 따라서 함수 포인터는 그 자체가 객체이며 그들이 가리키는 것은 아닙니다.

따라서 새로운 표현식을 통해 함수 포인터 유형의 객체를 만들 수 있습니다.


9

그것들은 (함수 포인터) void * 포인터에 저장할 수 없기 때문에.

실제로 함수 포인터를 a로 저장하는 void*것은 조건부로 지원됩니다. 이는 언어 구현에 따라 저장 될 수 있거나 저장 될 수 없음을 의미합니다. 언어 구현이 동적로드를 지원하는 경우 함수 포인터 변환 void*이 지원 될 수 있습니다. GCC, Clang 및 MSVC는 모두 다음을 지원합니다.

reinterpret_cast<void*>(&function);

함수에 대한 포인터를 새로 할당하는 것이 합법적입니까?

확실한. 함수 포인터를 포함한 모든 포인터는 객체이며 모든 객체는 동적으로 할당 될 수 있습니다.

또한 함수 포인터에 대한 결과 포인터는 일반 데이터 포인터로 작동합니다.

함수 포인터는 객체입니다. 함수 포인터뿐만 아니라 "로 동작"의 포인터,하지만 입니다 객체에 대한 포인터.

void *에 저장하고 static_cast에 의해 void *에서 검색 할 수 있습니다. 이 행동은 표준에 의해 보장됩니까?

void에 대한 포인터와 객체에 대한 포인터 사이의 변환은 허용됩니다. 그리고 왕복 변환은 원래 포인터를 생성하도록 보장됩니다.


감사. 그러나 함수 포인터를 void * (또는 다른 방법으로)로 변환하려면 reinterpret_cast를 사용해야합니다.
애드리안

1
@Adrian 예. 예를 추가했습니다.
eerorika

누군가 예외를 원한다면 중간 메모리 모델 + 오버레이를 수행하십시오. 함수 포인터는 중간 모델의 데이터 포인터보다 크고 오버레이를 사용하면 충분히 노력하면 플러그인을 얻을 수 있습니다.
여호수아
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.