C ++ 20'ye kadar tanımsız davranış için malloc kullanıyor


96

Aşağıdaki kodun C ++ 20'ye kadar tanımsız davranışa sahip olduğu söylendi:

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

Bu doğru mu?

Argüman, intdeğer atanmadan önce nesnenin yaşam süresinin başlamamasıydı ( P0593R6 ). Sorunu çözmek için yerleşim newkullanılmalıdır:

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

Nesnenin yaşam süresini başlatmak için gerçekten önemsiz bir varsayılan kurucu çağırmamız gerekiyor mu?

Aynı zamanda, kodun saf C'de tanımsız davranışı yoktur. Peki ya bir intC kodunu ayırıp C ++ kodunda kullanırsam?

// 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;

Hâlâ tanımlanmamış bir davranış mı?


8
İçin int? Hayır. Ne için std::string? Evet.
Eljay

8
@Eljay For int, ayrıca evet. Sadece yapmazsanız pratikte sorun yaratmaz. Çünkü std::string, açıkça sorunlara neden olacaktır.
Barry

Pre C ++ 20 yeni bir yerleşim ekleyebilirsiniz. O zaman iyi şekillenir ve muhtemelen hiçbir maliyeti olmaz.
François Andrieux

8
C ++ 20'de bunu değiştiren yeni kurallar nelerdir?
Kevin

4
Olması gerekmiyor int *p = (int*)malloc(sizeof(int)); p = new(p) int;mu? Bir keresinde yeni yerleştirmenin sonucunu atamamanın da ölümcül etkilere neden olabileceğini fark ettim (biraz aptalca görünse de).
Scheff

Yanıtlar:


62

Bu doğru mu?

Evet. Teknik olarak konuşursak, şunların parçası yok:

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

aslında bir tür nesnesi yaratır int, bu nedenle başvurudan çıkarma UB'dir p, çünkü orada gerçek intyoktur.

Nesnenin yaşam süresini başlatmak için gerçekten önemsiz olan varsayılan kurucu çağırmak zorunda mıyız?

Eğer Do zorunda tanımsız davranış öncesi C ++ 20 kaçınmak için C ++ nesne modeli başına? Evet. Herhangi bir derleyici bunu yapmadığınız için gerçekten zarar verecek mi? Farkında olduğumdan değil.

[...] Hala tanımlanmamış bir davranış mı?

Evet. C ++ 20 öncesi, aslında inthiçbir yerde bir nesne yaratmadınız, bu yüzden bu UB.


Yorumlar uzun tartışmalar için değildir; bu konuşma sohbete taşındı .
Makyen

Timsong-cpp.github.io/cppwp/n3337/basic.life#1.1'deki dil UB olmaması için neden yeterli değil? Sonuçta int, örnekte uygun boyutta ve hizalamada depolama elde edildi - intnesnenin ömrü burada başlıyor.
avakar

41

Evet, UB idi. intVarolma yollarının listesi numaralandırıldı ve malloc'un nedensiz olduğunu düşünmediğiniz sürece hiçbiri orada geçerli değildir.

Yaygın olarak standartta bir kusur olarak kabul edildi, ancak düşük önemde biriydi, çünkü C ++ derleyicileri tarafından belirli bir UB biti etrafında yapılan optimizasyonlar bu kullanım durumunda sorunlara neden olmadı.

2. soruya gelince, C ++, C ++ ve C'nin nasıl etkileşime girdiğini zorunlu kılmaz. Yani C ile tüm etkileşim ... UB, yani C ++ standardı tarafından tanımlanmamış davranış.


5
Bir int'in var olması için numaralandırılmış yollar listesini genişletebilir misiniz? İlkel tiplerin yaşam süreleri hakkında benzer bir soru sorduğumu ve bir ilkelin sadece onun var olduğunu söyleyerek "var olabileceğinin" söylendiğini hatırlıyorum çünkü şartname aksini söylemiyordu. Spesifikasyonun faydalı bir bölümünü kaçırmışım gibi görünüyor! Hangi bölümü incelemem gerektiğini bilmek isterim!
Cort Ammon

7
@CortAmmon C ++ 20'de bir nesnenin (herhangi bir türden) varolması için numaralandırılmış yollar listesi [intro.object] 'dedir : (1) tanım gereği (2) yeni kurallara göre örtük olarak yeni ifade (3) P0593 (4) 'te bir sendikanın (5) aktif üyesini geçici olarak değiştirmek. (3) C ++ 20'de yenidir, (4) C ++ 17'de yenidir.
Barry

3
C / C ++ etkileşimi gerçekten UB midir? Tanımsız olmaktan ziyade uygulama tanımlı olmak daha mantıklı olacaktır, aksi takdirde extern "C"sözdizimine sahip olmak bile tuhaf olurdu .
Ruslan

4
@Ruslan: Uygulamalar, ISO C ++ 'ın tanımsız bıraktığı herhangi bir davranışı tanımlamakta serbesttir. (Örneğin gcc -fno-strict-aliasingveya varsayılan olarak MSVC). "Uygulama tanımlandı" demek, tüm C ++ uygulamalarının, bazı C uygulamalarıyla birlikte çalışacakları bir yol tanımlamasını gerektirecektir , bu nedenle, böyle bir şey yapmak isteyip istemediklerine bakmaksızın, tamamen uygulamaya bırakmak mantıklıdır.
Peter Cordes

4
@PeterCordes: Neden bu kadar çok insanın IDB ve UB arasındaki bu ayrımı fark edemediğini merak ediyorum ve Standard'ın tüm uygulamaların bir yapıyı işlediğini zorunlu kılma konusundaki başarısızlığının, hiçbir uygulamanın bunu yapması beklenmemesi gerektiği yönünde bir yargıya işaret ettiği şeklindeki hayali bir fikri benimsiyorum. ve bunu yapmayan uygulamalar, sonuç olarak aşağı olarak görülmemelidir.
supercat
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.