C ++ 20까지 int 정의되지 않은 동작에 malloc을 사용하고 있습니다.


95

다음 코드는 C ++ 20까지 정의되지 않은 동작이 있다고 들었습니다.

int *p = (int*)malloc(sizeof(int));
*p = 10;

사실인가요?

인수는 int값을 할당하기 전에 객체 의 수명이 시작되지 않는다는 것입니다 ( P0593R6 ). 문제를 해결하려면 배치를 new사용해야합니다.

int *p = (int*)malloc(sizeof(int));
new (p) int;
*p = 10;

개체의 수명을 시작하기 위해 간단한 기본 생성자를 호출해야합니까?

동시에 코드는 순수 C에서 정의되지 않은 동작을 가지고 있지 않습니다. 그러나 intC 코드에서를 할당하고 C ++ 코드에서 사용하면 어떻게 될까요?

// C source code:
int *alloc_int(void)
{
    int *p = (int*)malloc(sizeof(int));
    *p = 10;
    return p;
}

// C++ source code:
extern "C" int *alloc_int(void);

auto p = alloc_int();
*p = 20;

여전히 정의되지 않은 동작입니까?


8
들어 int? 아니요 std::string. 예.
— Eljay

8
@Eljay For int, 또한 그렇습니다. 그것은 당신이 그것을하지 않으면 실제로 문제를 일으키지 않을 것입니다. 의 경우 std::string분명히 문제가 발생합니다.
— Barry

C ++ 20 이전에는 새로운 배치를 추가 할 수 있습니다. 그러면 잘 형성되고 아마도 비용이 들지 않을 것입니다.
— François Andrieux

8
이것을 변경하는 C ++ 20의 새로운 규칙은 무엇입니까?
— Kevin

4
안 int *p = (int*)malloc(sizeof(int)); p = new(p) int;그래? 새로운 배치 결과를 할당하지 않으면 치명적 효과도 발생할 수 있다는 것을 깨달았습니다 (조금 어리석게 보일 수 있지만).
— Scheff

답변:


61

사실인가요?

예. 기술적으로 말하면 다음의 일부가 아닙니다.

int *p = (int*)malloc(sizeof(int));

실제로 유형의 객체를 생성 int하므로 p실제가 없기 때문에 역 참조 는 UB int입니다.

객체의 수명을 시작하기 위해 사소한 기본 생성자를 호출해야합니까?

당신이 할 에이 정의되지 않은 동작이 사전 C ++ (20)을 방지하기 위해 C ++ 객체 모델 당? 예. 이 작업을 수행하지 않으면 실제로 컴파일러가 해를 입힐 수 있습니까? 내가 아는 것은 아닙니다.

[...] 여전히 정의되지 않은 동작입니까?

예. C ++ 20 이전 버전에서는 실제로 int어디에도 객체를 생성하지 않았 으므로 이것은 UB입니다.


의견은 확장 된 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
— Makyen

timsong-cpp.github.io/cppwp/n3337/basic.life#1.1 의 언어 가 UB 가 아니기에 충분 하지 않은 이유는 무엇 입니까? 결국, int예제에서 적절한 크기와 정렬의 저장이 얻어 int졌습니다. 객체 의 수명 이 거기서 시작됩니다.
— avakar

41

네, UB였습니다. int존재할 수 있는 방법의 목록 이 열거되었으며 malloc이 인과 적이라고 생각하지 않는 한 거기에는 적용되지 않습니다.

이는 표준의 결함으로 널리 간주되었지만 그 특정 비트에 대한 C ++ 컴파일러가 수행 한 최적화가 해당 사용 사례에 문제를 일으키지 않았기 때문에 중요도가 낮습니다.

두 번째 질문에 대해 C ++는 C ++와 C가 상호 작용하는 방식을 요구하지 않습니다. 따라서 C와의 모든 상호 작용은 ... UB, 일명 C ++ 표준에 정의되지 않은 동작입니다.


5
int가 존재하는 방법의 열거 된 목록을 확장 할 수 있습니까? 프리미티브 타입의 수명에 대해 비슷한 질문을했던 기억이나요. 스펙이 달리 말하지 않았기 때문에 프리미티브가 단순히 존재한다고 말함으로써 "존재"할 수 있다는 말을 들었던 기억이 있습니다. 사양의 유용한 섹션을 놓친 것 같습니다! 어떤 섹션을 숙독해야하는지 알고 싶습니다!
— 콜트 암몬

7
@CortAmmon 객체 (모든 유형)가 C ++ 20에 존재하는 방법의 열거 된 목록은 [intro.object]에 있습니다 . (1) 정의에 따라 (2) new-expression에 의해 (3) 암시 적으로 새 규칙에 따라 P0593에서 (4) 노조의 활성 구성원 변경 (5) 임시. (3)은 C ++ 20의 새로운 기능, (4)는 C ++ 17의 새로운 기능입니다.
— Barry

3
C / C ++ 상호 작용이 정말 UB입니까? 정의되지 않은 것보다 구현 정의되는 것이 더 합리적입니다. 그렇지 않으면 extern "C"구문이 전혀 없는 것이 이상 할 것 입니다.
— Ruslan

4
@Ruslan : 구현은 ISO C ++에서 정의되지 않은 동작을 정의 할 수 있습니다. (예 : gcc -fno-strict-aliasing또는 기본적으로 MSVC). "구현 정의 된 것"이라고 말하는 이 필요 그들이 그 여부 등의 작업을 수행 할 것인지 여부를 완전히까지 구현 떠나 의미가 있도록 모든 C ++를 구현하는 것은, 그들이 어떤 C 구현과 상호 운용하는 몇 가지 방법을 정의합니다.
— Peter Cordes

4
@PeterCordes : 왜 그렇게 많은 사람들이 IDB와 UB 사이의 구별을 인식하지 못하는지 궁금합니다. 그리고 표준이 모든 구현이 구조를 처리하도록 명령하지 않은 것은 어떤 구현도 그렇게 할 것으로 기 대해서는 안된다는 판단을 의미한다는 공상적인 개념을 채택합니다. 그렇게하지 않는 구현은 결과적으로 열등한 것으로 간주되어서는 안됩니다.
— supercat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.