Bitişik üyelerin sınıflarda çakışmasını ne önler?


12

Aşağıdaki üçü düşünün struct:

class blub {
    int i;
    char c;

    blub(const blub&) {}
};

class blob {
    char s;

    blob(const blob&) {}
};

struct bla {
    blub b0;
    blob b1;
};

int4 bayt olan tipik platformlarda , boyutlar, hizalamalar ve toplam dolgu 1 aşağıdaki gibidir:

  struct   size   alignment   padding  
 -------- ------ ----------- --------- 
  blub        8           4         3  
  blob        1           1         0  
  bla        12           4         6  

1 boyutu prensipte dolguya "sığabilse bile " blubve blobüyelerin depolanması arasında herhangi bir çakışma yoktur .blobblub

C ++ 20 no_unique_address, bitişik boş üyelerin aynı adresi paylaşmasına izin veren özniteliği sunar. Aynı zamanda, yukarıda açıklanan senaryoya göre bir üyenin diğerini depolamak için dolgusu kullanmasına izin verir. Gönderen cppreference (vurgu benim):

Bu veri üyesinin, sınıfındaki diğer tüm statik olmayan veri üyelerinden farklı bir adrese sahip olması gerekmediğini gösterir. Bu, eğer üyenin boş bir türü (örneğin vatansız Allocator) varsa, derleyicinin boş bir taban gibi boş yer kaplamayacak şekilde optimize edebileceği anlamına gelir. Eğer üye boş değilse, içindeki herhangi bir kuyruk dolgusu başka veri üyelerini saklamak için tekrar kullanılabilir.

Gerçekten, eğer bu niteliği kullanırsak blub b0, bladamla büyüklüğü 8, bu yüzden blobgerçekten blub godbolt üzerinde görüldüğü gibi saklanır .

Sonunda soruma geçelim:

Standartlardaki hangi metin (C ++ 11 - C ++ 20) no_unique_address, önemsiz şekilde kopyalanamayan nesneler için bu çakışmayı önler ?

TC nesneleri için, std::memcpyüye alt nesneler de dahil olmak üzere bir nesneden diğerine izin verilir ve depolama üst üste binmişse bu ( bitişik üye üzerine yazılır) 2 .


1 Dolguyu, basitçe, tüm yapı elemanlarının yapı boyutu ile boyutu arasındaki fark olarak, özyineli olarak hesaplıyoruz.

2 yapmak için: Ben kopya kurucular tanımlanmış olmasının nedeni budur blubve blobdeğil trivially copyable .


Araştırmadım, ama sanki "sanki" kuralını tahmin ediyorum . Soyut makinede gözlemlenebilir bir fark (çok özel bir anlama sahip bir terim btw) yoksa (kodunuzun karşılandığı budur), derleyici kodu istediği gibi değiştirebilir.
Jesper Juhl

Bunun bunun bir kopyası olduğuna eminim: stackoverflow.com/questions/53837373/…
NathanOliver

@JesperJuhl - ama neden yapamıyorum , neden yapamadığımı ve "sanki" kuralı genellikle birincisi için geçerli ama ikincisi için bir anlam ifade etmiyor. Ayrıca, yerel bir sorun değil, genellikle küresel bir sorun olan yapı düzeni için "sanki" net değildir. Nihayetinde derleyicinin düzen için tek bir tutarlı kurallar kümesi olması gerekir, belki de asla "kaçamayacağını" kanıtlayamayacağı yapılar hariç.
BeeOnRope

1
@BeeOnRope Sorunuza cevap veremiyorum, üzgünüm. Bu yüzden bir cevap değil, sadece bir yorum gönderdim. Buna ne yorumunda var bir açıklama doğru en iyi tahmin, ama yok biliyorum cevap (- ki bir upvote var neden currious kendim öğrenmeye).
Jesper Juhl

1
@NicolBolas - doğru soruyu cevaplıyor musunuz? Bu güvenli kopyaları veya başka bir şeyi tespit etmekle ilgili değildir. Bunun yerine, dolguların neden üyeler arasında tekrar kullanılamayacağını merak ediyorum. Her durumda, yanılıyorsunuz: önemsiz bir şekilde kopyalanabilir tipte bir özelliktir ve her zaman olmuştur. Ancak, bir nesneyi güvenli bir şekilde kopyalamak için her ikisinin de bir TC türüne (türün bir özelliği) sahip olması ve potansiyel olarak çakışan bir konu olmaması gerekir (nesnenin, karıştırdığınız yer olduğu bir özelliği) olmamalıdır. Buradaki kopyalar hakkında neden konuştuğumuzu hala bilmiyoruz.
BeeOnRope

Yanıtlar:


1

Bellek modeli hakkında konuşurken standart oldukça sessizdir ve kullandığı bazı terimler hakkında çok açık değildir. Ama bence bir çalışma argümanı buldum (bu biraz zayıf olabilir)

İlk olarak, bir nesnenin parçası olan şeyin ne olduğunu bulalım. [basic.types] / 4 :

Tür nesnesinin nesne temsili, tür nesnesi tarafından alınan nesnelerin Tdizisidir , burada eşittir . Bir tür nesnenin değer temsili, bir tür değerini temsil etmeye katılan bitler kümesidir . Nesne temsilindeki, değer temsilinin bir parçası olmayan bitler dolgu bitleridir.N unsigned charTNsizeof(T)TT

Yani nesnenin temsili nesnelerden b0oluşur sizeof(blub) unsigned char, yani 8 bayt. Dolgu bitleri nesnenin bir parçasıdır.

İçinde yuvalanmış değilse hiçbir nesne bir başkasının alanını işgal edemez [basic.life] /1.5 :

Bir otür nesnenin ömrü şu Tdurumlarda sona erer:

[...]

(1.5) nesnenin kapladığı depolama alanı serbest bırakılır veya içinde yuvalanmayan bir nesne tarafından yeniden kullanılır o([intro.object]).

Bu yüzden, kullanım b0alanı, başka bir nesne tarafından yeniden kullanıldığında, yani b1. Bunu kontrol etmedim, ancak standart olan bir nesnenin canlı olan alt nesnesinin de canlı olması gerektiğini düşünüyorum (ve bunun nasıl farklı çalışması gerektiğini hayal edemiyorum).

Bu yüzden b0 kaplayan depolama tarafından kullanılmayabilir b1. Standartta "işgal etmek" için bir tanım bulamadım, ama bence makul bir yorum "nesne gösteriminin bir parçası" olacaktır. Alıntı tanımlayıcı nesne temsili, "almak" kelimeleri kullanılır 1 . Burada, bu 8 bayt olacaktır, bu yüzden blaen az bir tane daha gerekiyor b1.

Özellikle alt nesneler için (diğer statik olmayan veri üyeleri arasında) aynı zamanda şartname [intro.object] / 9 da vardır (ancak bu C ++ 20, thx @BeeOnRope ile eklenmiştir)

Bit alanları olmayan örtüşen yaşam sürelerine sahip iki nesne, biri diğerinin içine yerleştirilmişse veya en az biri sıfır boyutlu bir alt nesne ise ve farklı türdeyse aynı adrese sahip olabilir; aksi takdirde farklı adresleri vardır ve ayrık bayt depolama alanı işgal ederler .

(benim vurgu) Burada tekrar, "işgal" tanımlanmamış sorunu var ve yine nesne temsil bayt almak için tartışmak istiyorum. Bu [basic.memobj] / dipnot 29 için bir dipnot olduğunu unutmayın

“İf-if” kuralı kapsamında, programın farkı gözlemleyememesi durumunda bir uygulamanın aynı makine adresinde iki nesne saklamasına veya hiçbir nesneyi saklamamasına izin verilir ([intro.execution]).

Bu, derleyicinin gözlemlenebilir bir yan etkisi olmadığını kanıtlayabilirse bunu kırmasına izin verebilir. Bunun nesne düzeni gibi temel bir şey için oldukça karmaşık olduğunu düşünürdüm. Belki de bu optimizasyon sadece kullanıcı [no_unique_address]özniteliği ekleyerek ayrık nesneler olması için hiçbir neden olmadığını bilgi verdiğinde alınır .

tl; dr: Dolgu belki nesnenin bir parçasıdır ve üyelerin ayrık olması gerekir.


1 Yer işgal etmek anlamına gelebilecek bir referans eklemeye dayanamadım: Webster's Revised Unabridged Dictionary, G. ve C. Merriam, 1913 (vurgu mayını)

  1. Boyutlarını tutmak veya doldurmak için; almak için oda veya alanını; örtmek veya doldurmak; kamp beş dönümlük bir alanı kaplar. Efendim J. Herschel.

Sözlük taraması olmadan hangi standart tarama tamamlanır?


2
İnto.storage'dan "ayrık depolama alanı bayt" kısmı, bence, benim için yeterli olacaktır - ancak bu ifade, eklenen değişikliğin bir parçası olarak yalnızca C ++ 20'de eklendi no_unique_address. C ++ 20'den önceki durumu daha az açık bırakır. Basic.life/1.5, "nesnenin kapladığı depolama alanı serbest bırakılır" dan "nasıl bir nesne onun içinde yuvalanmış değilse başka birinin alanını işgal edemez" diye anlamadım. "hiçbir nesne bir başkasının boşluğunu işgal edemez".
BeeOnRope

1
Bu paragrafa küçük bir açıklama ekledim. Umarım bu daha anlaşılır olur. Aksi takdirde yarın tekrar bakacağım, şu an benim için çok geç.
n314159

"Bit alanları olmayan çakışan yaşam süreleri olan iki nesne, biri diğerinin içine yerleştirilmişse veya en az biri sıfır boyutlu bir alt nesne ise ve farklı türdeyse aynı adrese sahip olabilirler" aynı türde, aynı adrese sahip .
Dil Avukatı

Üzgünüm, biraz ayrıntı verebilir misiniz? Cevabımdan standart bir fiyat teklifi alıyorsunuz ve bununla biraz çelişen bir örnek getiriyorsunuz. Bunun cevabım hakkında bir yorum olup olmadığından ve bana söylemesi gerekenden emin değilim. Örneğinizle ilgili olarak, standardın diğer kısımlarını da dikkate almak zorunda olduğumu söyleyebilirim (başka bir nesne için depolama sağlayan imzasız bir karakter dizisi hakkında bir paragraf var, sıfır boyutlu taban optimizasyonu ile ilgili bir şey var ve yine yeni bir yerleşim olup olmadığını da bakmalı özel ödenekler, bence her şey OP örneği ile ilgilidir)
n314159

@ n314159 Bence bu ifade arızalı olabilir.
Dil Avukatı
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.