C++ 포인터 주소값 저장하기
간혹 포인터의 주소 연산자 (&)를 이용하여 역참조 등을 할 일이 있다.
근데 절대 기억하지 못하는 특정 개체를 해제하지 않고 주소만으로 불러와야할 때도 있다.
어떤 값의 주소를 이용하여 역참조를 해보자.
Foo.h
class Foo { public: Foo(const int value); ~Foo(); int getValue(); private: int value; };
우리가 잃어버릴 클래스다. value 변수는 생성자에서 설정한 value로 설정된다.
Testsuite.cc
#include <iostream> #include <cstdint> #include <sstream> #include <string> #include "Foo.h" int main() { Foo foo(10); std::cout << &foo << std::endl; std::string dataAddress; { std::ostringstream ostream; ostream << reinterpret_cast<std::uintptr_t>(&foo); dataAddress = ostream.str(); } std::cout << dataAddress << std::endl; std::uintptr_t p; { std::istringstream istream(dataAddress); istream >> p; } std::cout << p << std::endl; Foo *lost = (Foo *) reinterpret_cast(p); std::cout << lost->getValue() << std::endl; return 0; };
굳이 std::string을 시용하여 주소를 저장해야하는지, 그건 필요에 따라 다를 것이다.
JNI와 같이 Java한테는 주소값을 넘겨줄만한 적당한 타입이 존재하지 않는다.
uintptr_t를 구현해서 Java에서 C++과 같이 주소를 저장하고 있다 다시 돌아와서 그 객체를 풀고 맞게 주소를 불러오기 보단
그냥 std::string <-> java.lang.String을 하는 것이 훨씬 나을 것이다.
하다못해 Java에서도 Unsafe 클래스를 이용하여 메모리 주소값으로 생성된 객체를 불러올 수 있는데
Native 언어로 그러지 못할리는 없을 것이다. 조금 불친절할 뿐이지.
추가1) 간혹 std::uintptr_t를 일반적인 primitive type으로 사용하는 방법에 대해서 묻는데, 이건 대상 플랫폼과 운영체제의 선언에 따라 다르다. 예를 들어 MSVC는 64비트에 unsigned __int64, 32비트에 unsigned int로 선언했고 GCC는 64비트에 unsigned long int, 32비트에 unsigned int로 선언되어있다. 필요에 따라 사용해야할 것이다.
추가2) 또한 이 기능 자체가 C++11부터 표준이 된 기능이다. 이전 표준에 대해서는 <cstdint>가 아닌<stdint.h>라는 C헤더를 이용해서 작성해야한다.