Ömrü sona eren bir nesnenin üye işlev programına devam etmek UB mi?


9

Bu soru şu yorumdan kaynaklanıyor: C ++ 20 programları için Lambda ömür boyu açıklama

bu örnekle ilgili olarak:

auto foo() -> folly::coro::Task<int> {
    auto task = []() -> folly::coro::Task<int> {
        co_return 1;
    }();
    return task;
}

Yani soru, geri dönen koroutinin yürütülmesinin fooUB ile sonuçlanıp sonuçlanmayacağıdır.

Bir üye işlevini "çağırma" (nesnenin ömrü bittikten sonra) UB: http://eel.is/c++draft/basic.life#6.2

... nesnenin bulunduğu veya bulunduğu depolama konumunun adresini temsil eden herhangi bir işaretçi kullanılabilir, ancak yalnızca sınırlı yollarla. [...] Program şu durumlarda tanımsız bir davranışa sahiptir:

[...]

- işaretçi, statik olmayan bir veri üyesine erişmek veya nesnenin statik olmayan bir üye işlevini çağırmak için kullanılır veya

Ancak, bu örnekte:

  • ()lambda ömrü hala geçerli iken lambda operatörü denir
  • Daha sonra askıya alınır,
  • sonra lambda yok edilir,
  • ve sonra üye fonksiyonu (operatör ()) daha sonra bir noktada devam eder.

Bu yeniden başlama tanımsız davranış olarak kabul edilir mi?


2
Belki de aşağıdaki cevap konuyla ilgilidir stackoverflow.com/a/60495359/12345656 Oldukça farklı görünüyor, ancak aynı zamanda thisişaretçinin yürütülmesi geçersiz kılınan bir üye işlevi ile ilgili . Yorumlardaki tartışmayı da düşünün.
n314159

Yanıtlar:


2

[dcl.fct.def.coroutine] p3 :

Söz türü bir eşyordamın olup std::coroutine_traits<R, P1, ..., Pn>::promise_typeburada, Rfonksiyonun dönüş türüdür ve P1 ... Pnfonksiyon parametrelerinin türleri sekansı olan örtülü bir amacı parametresinin türü öncesinde (12.4.1) eşyordam olmayan bir statik olduğu üye işlevi.

Örtük nesne parametresi örneğinizde bir const başvurusudur ve bu nedenle, kapatma nesnesi yok edildikten sonra yürütme sürdürüldüğünde bu başvuru sallanır.

Bununla birlikte, bir üye işlevinin yürütülmesi sırasında imha edilen nesneler söz konusu olduğunda, bu aslında kendiliğinden iyidir ve standarttan başka hiçbir şey bunu [temel] 'de ima etmez :

Bir nesnenin ömrü başlamadan önce, ancak nesnenin kaplayacağı depolama alanı ayrıldıktan sonra veya bir nesnenin ömrü sona erdikten sonra ve nesnenin bulunduğu depolama alanı yeniden kullanılmadan veya serbest bırakılmadan önce, adresini gösteren herhangi bir işaretçi nesnenin bulunacağı veya bulunduğu depolama yeri kullanılabilir, ancak yalnızca sınırlı yollarla. [...]

void B::mutate() {
  new (this) D2;    // reuses storage --- ends the lifetime of *this
  f();              // undefined behavior
  ... = this;       // OK, this points to valid memory
}

(Not: yukarıdaki UB, örtük thisçamaşırların yıkanmaması ve yine de örtük nesne parametresini ifade etmesidir.)

Dolayısıyla, örneğin, yürütmenin yeniden başlamasının orijinal bir çağrıyla aynı kurallara uymadığı fikrine bağlı olarak, örneğiniz iyi tanımlanmış görünüyor. Kapatma nesnesine yapılan başvurunun sarkık olabileceğini, ancak askıya alma ile yeniden başlatma arasında hiçbir şekilde erişilmediğini unutmayın.


Sonunda “devam etme ve tamamlama” mı demek istediniz?
Davis Herring

@DavisHerring Hayır, özellikle referansın gerçek bir nesne gerektiren yeni bir referansa vs. atanıp atanamayacağı açık olmayan "dış" zaman dilimi içinde kastediyorum. Referansın gizli bir şekilde erişilmemesi, bunun UB olmaması için önemlidir
Columbo

Ancak, yeniden başlatılıncaya kadar sarkan referansı yalnız bırakmak yeterli değildir; sonsuza dek yalnız bırakmalısınız ( örn . lambda gövdesinde) - ömrünün geri kalanında, yani tamamlanana kadar. Yani belki de “askıya alma ve tamamlama” olmalıdır.
Davis Herring

@DavisHerring Bu aralıktan özellikle bahsettim, çünkü örneğimizde diğerinin güvenli olduğunu biliyoruz.
Columbo

Elbette; Ben sadece kafa karıştırıcı buluyorum. Belki başka kimse yapmaz.
Davis Herring
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.