기본적으로 C++이 객체를 메모리에 배치하는 방법에 대해 궁금합니다. 그래서, 나는 동적 캐스팅이 단순히 오프셋을 사용하여 메모리에서 객체의 포인터를 조정한다는 것을 듣습니다. 종류의 재 해석은 우리가이 포인터로 무엇이든 할 수있게합니다. 나는 이것을 정말로 이해하지 못한다. 세부 사항은 평가 될 것이다!메모리 레이아웃 C++ 객체
답변
각 클래스는 선언 순서대로 데이터 멤버를 레이아웃합니다.
컴파일러는 효율적으로 액세스 할 수 있도록 멤버간에 패딩을 둘 수 있습니다 (하지만 재정렬은 허용되지 않습니다).
어떻게 dynamic_cast<>
작품은 컴파일러 구현 세부 사항이며 표준에 의해 정의되지 않았습니다. 그것은 모두 컴파일러에서 사용하는 ABI에 의존합니다.
reinterpret_cast<>
은 개체 유형을 변경하여 작동합니다. 당신이 작동한다는 것을 보장 할 수있는 유일한 것은 void *에 대한 포인터를 캐스팅하고 클래스에 대한 동일한 포인터로 돌아 가면 동일한 포인터를 줄 것입니다.
대답은 "복잡합니다"입니다. 동적 캐스트는 단순히 오프셋을 사용하여 포인터를 조정하는 것이 아닙니다. 작업을 수행하기 위해 객체 내부의 내부 포인터를 실제로 검색 할 수 있습니다. GCC는 Itanium 용으로 설계된 ABI를 따르지만 더 광범위하게 구현됩니다. 여기서 자세한 내용을 확인할 수 있습니다 : Itanium C++ ABI.
앞에서 설명한 것처럼 전체 내용은 복잡하고 읽기가 힘들며 컴파일러 개발자에게만 유용하며 컴파일러에 따라 다릅니다. 기본적으로 각 개체는 (보통 순서로 배치) 다음이 포함
- 런타임 타입 정보
- 비 가상베이스 객체 및 데이터 (아마 선언의 순서대로).
- 구성원 변수
- 가상 기본 개체 및 해당 데이터 (일부 DFS 트리 검색 순서 일 가능성이 있음).
이러한 데이터는 메모리 정렬을 쉽게하기 위해 채워질 수도 있고 그렇지 않을 수도 있습니다. 런타임 유형 정보에는 유형, 가상 부모 클래스 용 v 테이블 등에 대한 정보가 숨겨져 있습니다. 모두 컴파일러 관련 정보입니다. .
캐스팅의 경우 reinterpret_cast
은 단순히 포인터의 C++ 데이터 유형을 변경하고 다른 작업을 수행하지 않으므로 사용시 수행중인 작업을 잘 알고 있어야합니다. 그렇지 않으면 엉망이 될 가능성이 있습니다 나쁘게. dynamic_cast
은 런타임 유형 정보를 사용하여 주어진 유형으로 변환 할 수 있는지 알아내는 방법과이를 수행하는 방법을 제외하고는 static_cast (포인터 변경시)와 매우 똑같습니다. 다시 말하지만, 컴파일러마다 다릅니다. dynamic_cast
void*
은 런타임 유형 정보를 찾을 수있는 위치를 알아야하므로 모든 멋진 런타임 검사를 수행 할 수 있습니다.
이 질문에 이미 여기가에서 발췌 한 것입니다 http://dieharddeveloper.blogspot.in/2013/07/c-memory-layout-and-process-image.html 에 대한 답변 : 을 프로세스의 주소 공간의 중앙에서 지역 공유 객체를 위해 예약되어있다. 새로운 프로세스가 생성되면, 프로세스 관리자는 먼저 두 세그먼트를 실행 파일에서 메모리로 매핑합니다. 그런 다음 프로그램의 ELF 헤더를 디코딩합니다. 프로그램 헤더가 실행 파일이 공유 라이브러리에 링크 된 것으로 나타내면 프로세스 관리자 (PM)는 프로그램 헤더에서 동적 인터프리터의 이름을 추출합니다. 동적 해석기는 런타임 링커 코드가 포함 된 공유 라이브러리를 가리 킵니다.
귀중한 정보이지만 다른 질문에 답합니다. – domen
메모리 레이아웃은 대부분 구현에 맡겨져 있습니다. 중요한 예외는 지정된 액세스 지정자에 대한 멤버 변수가 선언 순서대로 존재한다는 것입니다. 이후 부재 클래스 오브젝트 내의 높은 주소를 갖도록
§ 동일한 액세스 제어 (11.)와 (비 연합) 클래스 9.2.14
비 정적 데이터 멤버가 할당된다. 서로 다른 접근 통제를 가진 비 정적 (non-static) 데이터 구성원들의 할당 순서는 명기되어 있지 않다. 구현 정렬 요구 사항으로 인해 인접한 두 멤버 이 서로 즉시 할당되지 않을 수 있습니다. 가상 기능 (10.3) 및 가상 기본 클래스 (10.1)를 관리하기위한 공간에 대한 요구 사항은 일 수 있습니다.
멤버 변수 이외에 클래스 또는 구조체는 멤버 변수, 기본 클래스의 하위 개체, 가상 함수 관리 (예 : 가상 테이블) 및 이러한 데이터의 패딩 및 정렬을위한 공간을 제공해야합니다. 이것은 구현에 달려 있지만 Itanium ABI 사양은 대중적인 선택입니다. gcc와 clang은 (적어도 어느 정도는) 그것을 고수한다.
http://mentorembedded.github.io/cxx-abi/abi.html#layout
아이테니엄 ABI
++는 물론 표준 C의 일부이며 바인딩되지 않습니다. 좀더 자세히 알려면 구현 자의 문서와 도구를 참조해야합니다. clang은 클래스의 메모리 레이아웃을 보는 도구를 제공합니다. 예를 들어 다음과 같습니다.class VBase {
virtual void corge();
int j;
};
class SBase1 {
virtual void grault();
int k;
};
class SBase2 {
virtual void grault();
int k;
};
class SBase3 {
void grault();
int k;
};
class Class : public SBase1, SBase2, SBase3, virtual VBase {
public:
void bar();
virtual void baz();
// virtual member function templates not allowed, thinking about memory
// layout and vtables will tell you why
// template<typename T>
// virtual void quux();
private:
int i;
char c;
public:
float f;
private:
double d;
public:
short s;
};
class Derived : public Class {
virtual void qux();
};
int main() {
return sizeof(Derived);
}
클래스의 메모리 레이아웃을 사용하는 소스 파일을 만든 후 clang이 메모리 레이아웃을 표시합니다.
$ clang -cc1 -fdump-record-layouts layout.cpp
Class
에 대한 레이아웃 :
*** Dumping AST Record Layout
0 | class Class
0 | class SBase1 (primary base)
0 | (SBase1 vtable pointer)
8 | int k
16 | class SBase2 (base)
16 | (SBase2 vtable pointer)
24 | int k
28 | class SBase3 (base)
28 | int k
32 | int i
36 | char c
40 | float f
48 | double d
56 | short s
64 | class VBase (virtual base)
64 | (VBase vtable pointer)
72 | int j
| [sizeof=80, dsize=76, align=8
| nvsize=58, nvalign=8]
이 연타 기능에 대한 자세한 엘리 Bendersky의 블로그에서 확인할 수 있습니다 :
http://eli.thegreenplace.net/2012/12/17/dumping-a-c-objects-memory-layout-with-clang/
GCC 비슷한 도구를 제공,`-fdump -class-hierarchy '를 참조하십시오.
Class Class
size=80 align=8
base size=58 base align=8
Class (0x0x141f81280) 0
vptridx=0u vptr=((& Class::_ZTV5Class) + 24u)
SBase1 (0x0x141f78840) 0
primary-for Class (0x0x141f81280)
SBase2 (0x0x141f788a0) 16
vptr=((& Class::_ZTV5Class) + 56u)
SBase3 (0x0x141f78900) 28
VBase (0x0x141f78960) 64 virtual
vptridx=8u vbaseoffset=-24 vptr=((& Class::_ZTV5Class) + 88u)
그것은 멤버 변수를 항목별로하지 않는 (또는 적어도 나는 그것을 얻을하는 방법을 알고하지 않습니다)하지만 당신은 그들이 것이라고 말할 수 있습니다 위의 클래스를 들면, (무엇보다도) 인쇄 clang 레이아웃 에서처럼 오프셋 28에서 64 사이 여야합니다.
하나의 기본 클래스가 primary
으로 선택되어 있음을 알 수 있습니다. 따라서 Class
에 액세스 할 때 SBase1
으로 this
포인터를 조정할 필요가 없습니다.GCC에 대한
등가은 다음과 같습니다
는$ g++ -fdump-class-hierarchy -c layout.cpp
비주얼 C++에 대한 것과 동일합니다 :
는cl main.cpp /c /d1reportSingleClassLayoutTest_A
- 1. objective-c 객체 메모리 관리
- 2. 파이썬 - "객체 레이아웃"
- 3. 자바와 메모리 레이아웃
- 4. 도스의 기본 메모리 레이아웃
- 5. 연속적인 메모리 덩어리에 objective-c 객체 할당
- 6. 메모리 타일링 관리 및 대용량 객체 C#
- 7. C++에서 중첩 클래스와 다중 상속의 메모리 레이아웃 차이점은 무엇입니까?
- 8. 정적 객체 메모리 해제
- 9. iPhone, 메모리/autorelease 객체
- 10. 객체 메모리 최적화 질문
- 11. C# 객체 인스턴스화
- 12. 객체 할당 및 메모리 경고
- 13. Objective-C 메모리 관리 - 객체 반환시 모범 사례?
- 14. 목표 - C : 객체 초기화하고 다음 코드를 감안할 때 메모리 관리
- 15. objective-c 메모리 관리
- 16. Mathematica 8에서 Graph [] 객체 자동 레이아웃 방지
- 17. Android 레이아웃 - 동일한 위치의 UI 객체
- 18. 첫 번째 중심이있는 플렉스 레이아웃 2 객체
- 19. 보기의 레이아웃 속성을 객체 컨트롤러에 바인딩
- 20. 메모리 게임을위한 GridView 대 기타 레이아웃 | Android
- 21. C# 패널 레이아웃 문제
- 22. C++ 멤버 레이아웃
- 23. C# WPF Stackpanel 레이아웃
- 24. C++ 0X "표준 레이아웃"
- 25. 메모리 누출의 C/메모리 할당 ++
- 26. C/C++ 메모리 문제?
- 27. 코코아의 로컬 객체 범위 및 메모리 관리
- 28. Objective-c 객체 해제 패턴
- 29. 공유 메모리에서 객체 인스턴스화하기 C++
- 30. 코코아 메모리 관리 - 객체 나 전무가는
첫 번째 포인트는 완전히 정확하지 않습니다. 유일한 액세스 보장은 동일한 액세스 블록의 멤버가 정의 된 순서를 갖게된다는 것입니다. 이를 극단적으로 생각하고 싶다면 액세스 권한이 동일해도 주문이 더 이상 보장되지 않는다고 말할 수 있습니다. –
@ 리차드. 내가 너를 이해하는지 모르겠다. 컴파일러는 요소를 재정렬 할 수 없습니다 (이것은 C와의 후방 호환성을위한 것입니다). 액세스 블록이란 무엇입니까? 정보를 얻고있는 표준의 올바른 부분을 지적 할 수 있습니까? –
액세스 블록 (실제로는 액세스 지정자)은 클래스에있는'public :','private :','protected :'입니다. 저는이 기사가 http://www.embedded.com/design/218600150?pgno=1 매우 유용하다는 것을 알았습니다. 그게 제가 리차드가 그의 말에서 언급 한 것을 처음 배웠던 곳입니다. 거기에 링크 된 C++ 표준을 찾아 보았습니다. 198 (초 9.2 절 12) 상태 : "액세스 제어가 다른 비 정적 데이터 멤버의 할당 순서가 지정되지 않았습니다." –