2016-08-17 1 views
4

최근에 C++ 할당자가 어떻게 작동하는지 이해하려고 시도했으며 STL 라이브러리가 std::set 또는 std::map과 같은 항목에 사용하는 빨강 - 검정 트리 구현을 조사했습니다. ,하지만 내 머리를 얻을 수없는 것들이 있습니다.C++ (STL 트리)에서 할당 자 사용

typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template 
    rebind<_Rb_tree_node<_Val> >::other _Node_allocator; 

typedef __gnu_cxx::__alloc_traits<_Node_allocator> _Alloc_traits; 

이 : _Val - - - _Rb_tree_node<_Val>을 - 리 바인드 템플릿을 사용하여 나무가 사용하는 노드의 유형 않습니다

우선은 컨테이너 저장하는 형식에서 할당을 변환입니다 나는 밖으로 분류 할 수있다. 요소가 삽입되고 그것이 무엇 새 노드를 만들 필요가

이제

, 나는 하나의 노드에 대한 할당 공간을 가정이

_Node_type __node = _Alloc_traits::allocate(_M_get_Node_allocator(), 1); 

입니다. __node위한 공간이 이미 할당되어 있기 때문에 그러나 그것은, 내가 정말 무엇을하는지 모르는이

::new(__node) _Rb_tree_node<_Val>; 

않습니다. 그러나 그것은 또한 가정 노드 (노드 할당입니다) 구성되어 있기 때문에, 나를 더욱 혼란하게이

_Alloc_traits::construct(_M_get_Node_allocator(), __node->_M_valptr(), ...); 

을 수행하지만, 유형 _Val*이다 포인터 __node->_M_valptr()를 통과 한 후 것이다.

누군가 설명 할 수 있다면 매우 감사하게 생각합니다.

+0

'operator new'는 메모리를 할당하지 않으며, 객체를 생성합니다 (그리고 때로는 메모리를 할당하지만, 당신의 경우는 아닙니다). 그래서, 두 번째 줄 (':: new (__ node) _Rb_tree_node <_Val>;)은 아마'__node' 할당 된 메모리 블록에 노드를 만들 것이라고 말하고 싶습니다. – alexeykuzmin0

+0

Ok, 왜 '__node' 포인터를 연산자에 전달합니까? 게다가, 노드를 생성한다면,':: construct()'는 나중에 무엇을 하는가? – gmardau

+0

"이유는 포인터를 전달하는 이유"? 답을 설명 할 때, 이것은 _placement'new'_ 구문입니다. 그리고 그것은 새로운 객체를 어디에서 찾을 것인가를 어떻게 알 수 있을까요? –

답변

6
::new(__node) _Rb_tree_node<_Val>; 

new expression이 형태의 '배치 새로운'이라고합니다. 새 메모리를 할당하지는 않지만 인수로 가리키는 메모리 영역에만 객체를 생성합니다. 여기서 __node은 노드에 이미 할당 된 메모리에 대한 포인터이며이 표현식은 _Rb_tree_node<_Val> 유형의 객체를이 위치에 구성합니다.

_Alloc_traits::construct(_M_get_Node_allocator(), __node->_M_valptr(), ...); 

메모리에 입력 _Val의 목적 __node->_M_valptr() 가리키는 라인이 constructs.

::new(__node) _Rb_tree_node<_Val>; 

+0

감사합니다. 마지막으로. '_M_valptr()'에 노드 할당자를 사용하는 이유는 다른 유형입니까? – gmardau

+0

@Mehlins'_M_valptr'의 타입은 무엇입니까? – user2296177

+0

'Val *'. 코드는 다음과 같습니다. '__gnu_cxx :: __ aligned_membuf <_Val> _M_storage; _Val * _M_valptr() {return _M_storage._M_ptr(); }' – gmardau

2

선은 단순히 주어진 메모리 어드레스에 __node)_Rb_tree_node<_Val>의 객체를 생성 placement new을 사용한다. 그러면 노드 객체가 생성됩니다.

이제 회원 중 한 명이 _M_valptr()으로해야합니다. 라인

_Alloc_traits::construct(_M_get_Node_allocator(), __node->_M_valptr(), ...); 

(간접적으로 호출) 글로벌 배치 new (사실, 일반적으로 그냥 호출)와 매우 유사하다 할당의 construct method. 따라서 다시 개체를 생성 할 위치에 대한 포인터를 사용합니다. 이것은 value 객체를 생성합니다.

+0

좋아, 그래서 전달할 값이 없기 때문에'new'라는 배치를 사용한다고 가정합니다. (:: construct()에서 필요합니다), 실제로는 :: :: construct() 함수를 사용합니다. 통과 할 가치가있는 ('... '안에 숨겨져있다.) 아직 얻지 못하는 한 가지가 있습니다. '_M_valptr()'에 노드 할당자를 사용하는 이유는 다른 유형입니까? – gmardau

+0

@Mehlins 이것은 실제 사용하는 정확한 표준 라이브러리 * 구현 *에 달려 있지만, 다시 한번 전역 적으로 새로운 배치를 간접적으로 호출하는 것이 거의 확실합니다. 노드 할당자를 통해 적절한 것을 호출하는 것을 어떻게 알 수 있습니까? 당신이 언급 한'rebind' 메카니즘을 통해, 함수 템플릿을 통해 등등. apperance에도 불구하고 노드 할당자를 근본적으로 사용하지 않습니다. –

2

"Placement New"을 사용하여 이미 할당 된 메모리에 객체를 구성 할 수 있습니다.

void * mem = malloc(sizeof(MyStruct)); 
MyStruct * my_struct_ptr = new(mem) MyStruct(/*Args...*/); 

/*Do stuff...*/ 

my_struct_ptr->~MyStruct();//Literally one of the only times a good programmer would ever do this! 
free(mem); 

또는 당신은 이런 식으로 쓸 수 :

char * mem = new char[sizeof(MyStruct)]; 
MyStruct * my_struct_ptr = new(mem) MyStruct(/*Args...*/); 

/*Do stuff...*/ 

my_struct_ptr->~MyStruct();//Literally one of the only times a good programmer would ever do this! 
delete mem; 

을 또는이 :

char mem[sizeof(MyStruct)]; 
MyStruct * my_struct_ptr = new(mem) MyStruct(/*Args...*/); 

/*Do stuff...*/ 

my_struct_ptr->~MyStruct();//Literally one of the only times a good programmer would ever do this! 

기본 개념은 이제 일반적으로 자동으로 처리 매뉴얼 정리에 대한 책임이 될 것입니다 언어 및 컴파일러. 할당 자와 작업 할 때 매우 좋은 연습 인 예외입니다. 좋은 할당자를 작성하려면 메모리 할당을 직접 제어해야합니다.