문제

나는 최근에 만났다 이 폭언.

나는이 기사에 언급 된 몇 가지 요점을 잘 이해하지 못한다.

  • 저자는 작은 성가심을 언급합니다 delete vs delete[], 그러나 솔루션을 제공하지 않고 실제로 (컴파일러를 위해) 실제로 필요하다고 주장하는 것 같습니다. 내가 뭐 놓친 거 없니?
  • '특수 할당 자'섹션에서 기능 f(), 할당을 다음과 같이 대체하면 문제를 해결할 수있는 것 같습니다. (정렬 생략)

    // if you're going to the trouble to implement an entire Arena for memory,
    // making an arena_ptr won't be much work. basically the same as an auto_ptr,
    // except that it knows which arena to deallocate from when destructed.
    arena_ptr<char> string(a); string.allocate(80);
    // or: arena_ptr<char> string; string.allocate(a, 80);
    arena_ptr<int> intp(a); intp.allocate();
    // or: arena_ptr<int> intp; intp.allocate(a);
    arena_ptr<foo> fp(a); fp.allocate();
    // or: arena_ptr<foo>; fp.allocate(a);
    // use templates in 'arena.allocate(...)' to determine that foo has
    // a constructor which needs to be called. do something similar
    // for destructors in '~arena_ptr()'.
    
  • '과부하의 위험 :: Operator New []'에서 저자는 new(p) obj[10]. 왜 대신 (훨씬 덜 모호한) :

    obj *p = (obj *)special_malloc(sizeof(obj[10]));
    for(int i = 0; i < 10; ++i, ++p)
        new(p) obj;
    
  • 'C ++의 메모리 할당 디버깅'. 여기서 논쟁 할 수 없습니다.

전체 기사는 수업을 중심으로 진행되는 것 같습니다 중요한 생성자 그리고 소멸자 a 사용자 정의 메모리 관리 체계. 그것이 유용 할 수 있지만 논쟁 할 수는 없지만 공통점이 매우 제한적입니다.

기본적으로 우리는 신규 및 클래스 당 할당자를 배치했습니다. 이러한 접근법으로 어떤 문제를 해결할 수 없습니까?

또한, 나는 단지 두껍고 미친 경우에 당신의 이상적인 C ++, 대체 할 것 operator new? 필요에 따라 구문을 발명하십시오 이상적인, 단순히 이러한 문제를 더 잘 이해하도록 도와줍니다.

도움이 되었습니까?

해결책

글쎄, 이상적인 아마도 어떤 종류의 삭제를 삭제할 필요가 없을 것입니다. 쓰레기 수집 환경을 갖추고 프로그래머가 전체 문제를 피하도록하십시오.

rant의 불만은

  1. "나는 Malloc이하는 방식이 마음에 들었다"
  2. "나는 알려진 유형의 개체를 명시 적으로 만들어야하는 것을 좋아하지 않는다"

그는 당신이 둘 다 구현해야한다는 성가신 사실에 대해 옳습니다. new 그리고 new[], 그러나 당신은 C의 의미론의 핵심을 유지하려는 Stroustrups의 욕구에 의해 강요당했습니다. 배열에서 포인터를 말할 수 없으므로 컴파일러를 직접 알리야합니다. 당신은 그것을 고칠 수 있지만, 그렇게하는 것은 언어의 C 부분의 의미를 근본적으로 바꾸는 것을 의미합니다. 더 이상 정체성을 사용할 수 없습니다

*(a+i) == a[i]

모든 C 코드의 매우 큰 하위 집합이 깨질 것입니다.

그래서 당신은 언어를 가질 수 있습니다

  • 배열에 대한보다 복잡한 개념을 구현하고 포인터 산술의 경이로움을 제거하여 마약 벡터 또는 유사한 것과 함께 배열을 구현합니다.

  • 쓰레기가 수집되었으므로 자신의 것이 필요하지 않습니다. delete 규율.

즉, Java를 다운로드 할 수 있습니다. 그런 다음 언어를 변경하여 확장 할 수 있습니다.

  • 강하게 입력되지 않으므로 확인하십시오 void * 업 캐스트가 제거되고

... 그러나 그것은 컴파일러가 보지 않고 foo를 막대로 변환하는 코드를 작성할 수 있음을 의미합니다. 원한다면 Ducktyping도 가능합니다.

문제는 일단 그런 일을 한 후에는 C-ish 구문이있는 Python 또는 Ruby가 있다는 것입니다.

Stroustrup이 Cfront 1.0의 테이프를 보냈기 때문에 C ++를 작성했습니다. C ++와 관련된 많은 역사는 이제 C 세계에 맞을 수있는 OO 언어를 갖고 싶어하는 욕구에서 나옵니다. 에펠과 같이 같은시기에 나온 다른 더 만족스러운 언어가 많이있었습니다. C ++가 이겼던 것 같습니다. 나는 그것이 이겼다고 생각한다 왜냐하면 C 세계에 맞을 수 있습니다.

다른 팁

IMHO는 매우 오해의 소지가 있으며 저자가 더 미세한 세부 사항을 이해하는 것 같습니다. 단지 그가 오도하고 싶어하는 것 같습니다. IMHO, 인수의 결함을 보여주는 핵심 요점은 다음과 같습니다.

void* operator new(std::size_t size, void* ptr) throw();

표준은 위의 함수에 다음 속성이 있음을 정의합니다.

보고: ptr.

메모: 의도적으로 다른 행동을 수행하지 않습니다.

이 기능을 다시 만들기 위해 의도적으로 다른 행동을 수행하지 않습니다. 이것은 새로운 배치가하는 일의 열쇠이기 때문에 매우 중요합니다. 객체의 생성자를 호출하는 데 사용됩니다. 이것이 전부입니다. 명시 적으로 주목하십시오 크기 매개 변수는 언급되지 않았습니다.

시간이없는 사람들을 위해, 나의 요점을 요약하기 위해 : c에서 'malloc'가하는 모든 일은 ":: operator new"를 사용하여 C ++에서 수행 할 수 있습니다. 유일한 차이점은 집계 유형이없는 경우 (즉)입니다. 소멸자와 생성자가 호출되어야하는 유형을 호출 한 다음 해당 생성자와 소멸자를 호출해야합니다. 이러한 유형은 C에는 명시 적으로 존재하지 않으므로 "Malloc이 더 잘 수행"한다는 주장을 사용하는 것이 유효하지 않습니다. 'C'에 구조물이있는 경우 특별한 "초기화"함수가있는 경우 해당 "DestroyMe"로 호출되어야합니다. 저자가 만든 모든 점은 해당 구조물이 아닌 C ++ 구조물과 동일하게 적용됩니다.

그의 포인트 중 일부를 명시 적으로 가져옵니다.

여러 상속을 구현하려면 컴파일러는 실제로 일부 캐스트 중에 포인터 값을 변경해야합니다. 무효로 변환 할 때 결국 원하는 값을 알 수 없습니다. 따라서 일반적인 기능은 C ++에서 Malloc의 역할을 수행 할 수 없습니다.

이것은 다시 맞지 않습니다 :: 운영자 역할을 수행합니다 Malloc:

class A1 { };
class A2 { };
class B : public A1, public A2 { };

void foo () {
    void * v = ::operator new (sizeof (B));
    B * b = new (v) B();  // Placement new calls the constructor for B.
    delete v;

    v = ::operator new (sizeof(int));
    int * i = reinterpret_cast <int*> (v);
    delete v'
}

위에서 언급했듯이 B의 생성자를 호출하려면 새로 배치해야합니다. 'I'의 경우 캐스트 할 수 있습니다. 무효의* 에게 int* 문제가 없으면 다시 배치를 사용하면 유형 확인이 향상됩니다.

그가하는 또 다른 요점은 정렬 요구 사항에 관한 것입니다.

New Char [...]에 의해 반환 된 메모리가 반드시 구조물 intlist의 정렬 요구 사항을 충족하지는 않습니다.

3.7.3.1/2 미만의 표준은 다음과 같이 말합니다.

반환 된 포인터는 완전한 객체 유형의 포인터로 변환 된 다음 할당 된 스토리지의 객체 또는 배열에 액세스하는 데 사용되도록 적절하게 정렬되어야합니다 (저장소가 해당 거래 기능에 대한 호출에 의해 명시 적으로 처리 될 때까지) .

나에게 꽤 분명해 보인다.

전문화 된 할당 자 하에서 저자는 당신이 가질 수있는 잠재적 인 문제를 설명합니다. 할당자를 메모리 자체를 할당하는 유형에 대한 인수로 사용해야하며 구성된 물체는 파괴자에게 명시 적으로 호출해야합니다. 다시 말하지만, 이것은 할당 자 객체를 "initalizeme"으로 전달하는 것과 C 구조물을 호출하는 것과 어떻게 다른가요?

Destructor를 호출하는 것과 관련하여 C ++에서는 특별한 종류의 스마트 포인터를 쉽게 만들 수 있습니다. "Placement_Pointer"라고 부를 수 있습니다. "Placement_Pointer"라고 부르겠습니다. 결과적으로 우리는 다음을 가질 수 있습니다.

template <typename T>
class placement_pointer {
  // ...
  ~placement_pointer() {
    if (*count == 0) {
      m_b->~T();
    }
  }
  // ...
  T * m_b;
};

void
f ()
{
  arena a;

  // ...
  foo *fp = new (a) foo;           // must be destroyed
  // ...
  fp->~foo ();

  placement_pointer<foo> pfp = new (a) foo; // automatically !!destructed!!
  // ...
}

내가 댓글을 달고 싶은 마지막 요점은 다음과 같습니다.

G ++는 다음과 같이 정의 된 "배치"연산자가 함께 제공됩니다.

inline void *
operator new[](size_t, void *place)
{
  return place;
}

위에서 언급 한 바와 같이, 이런 식으로 구현 될뿐만 아니라 표준에 따라야합니다.

obj를 소멸자가있는 수업으로합시다. 어딘가에 크기가 크기 (OBJ [10]) 바이트의 어딘가에 있고 해당 위치에 유형 OBJ의 10 개 객체를 구성하고 싶다고 가정 해 봅시다. (C ++는 크기 (OBJ [10])을 10 * sizeof (OBJ)로 정의합니다.이 배치 연산자 New []로 그렇게 할 수 있습니까? 예를 들어 다음 코드는 그렇게하는 것 같습니다.

obj *
f ()
{
  void *p = special_malloc (sizeof (obj[10]));
  return new (p) obj[10];       // Serious trouble...
}

불행히도이 코드는 올바르지 않습니다. 일반적으로, size_t 인수가 연산자에게 전달 된 인수가 실제로 할당되는 배열의 크기에 해당한다는 보장은 없습니다.

그러나 그가 정의를 공급함으로써 강조 표시되면, 크기 인수는 할당 함수에 사용되지 않습니다. 할당 함수가 있습니다 아무것도 아님 - 위의 배치 표현식의 유일한 영향은 예상대로 10 개의 배열 요소의 생성자를 호출하는 것입니다.

이 코드에는 다른 코드가 있지만 저자가 나열된 코드는 아닙니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top