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.