Sabit bağımsız değişkenin değerini const referansı ile döndürmek uygun mudur?


26

Aşağıdaki örneklerde olduğu gibi const referansıyla varsayılan bağımsız değişkenin değerini döndürmek uygun mudur:

https://coliru.stacked-crooked.com/a/ff76e060a007723b

#include <string>

const std::string& foo(const std::string& s = std::string(""))
{
    return s;
}

int main()
{
    const std::string& s1 = foo();
    std::string s2 = foo();

    const std::string& s3 = foo("s");
    std::string s4 = foo("s");
}

3
Basit test: std::stringYapım ve yıkımı takip edebilmek için kendi sınıfınızla değiştirin .
user4581301

1
@ user4581301 Eğer dizi doğruysa, yapının iyi olduğunu kanıtlamaz.
Peter - Monica'yı

6
@ user4581301 "Ben denediğimde işe yaradığı ortaya çıktı" undefined davranışı hakkında mutlak en kötü şey
HerrJoebob

Sorunun ifadesinde yanıltıcı bir tidbit olduğu belirtilmelidir. Varsayılan bir bağımsız değişkenin değerini const başvurusuyla döndürmüyorsunuz, ancak const başvurusuna (... varsayılan bir bağımsız değişkene) const başvurusu döndürüyorsunuz.
Damon

2
@HerrJoebob% 100 ifadesiyle aynı fikirde olun, ancak kullandığınız bağlamda değil. Bu soruyu okuma şeklim "Nesnenin ömrü ne zaman bitti?" yıkıcı arandığında bunu bulmak iyi bir yoldur. Otomatik değişken için yıkıcı tam zamanında çağrılmalıdır veya büyük sorunlarınız olur.
user4581301

Yanıtlar:


18

Kodunuzda, hem s1ve s3sarkan referanslardır. s2ve s4iyiyim.

İlk çağrıda, std::stringvarsayılan bağımsız değişkenten oluşturulan geçici boş nesne, çağrıyı içeren ifade bağlamında oluşturulur. Bu nedenle, sarkan s1bırakan tanımının sonunda ölecektir s1.

İkinci çağrıda, geçici std::stringnesne başlatmak için kullanılır s2, sonra ölür.

Üçüncü çağrıda, dizgi değişmezi "s"geçici bir std::stringnesne oluşturmak için kullanılır ve bu da tanımlamanın sonunda sarkan s3bırakarak ölür s3.

Dördüncü çağrıda, std::stringdeğeri olan geçici nesne "s"başlangıç ​​durumuna getirilir s4ve sonra ölür.

Bkz. C ++ 17 [class.temporary] /6.1

Bir işlev çağrısındaki (8.2.2) bir referans parametresine bağlı geçici bir nesne, çağrıyı içeren tam ifadenin tamamlanmasına kadar devam eder.


1
Yanıtın ilginç kısmı, varsayılan argümanın arayanın bağlamında oluşturulacağı iddiasıdır. Bu, Guillaume'nin standart alıntısıyla destekleniyor gibi görünüyor.
Peter - Monica'yı yeniden eski haline

2
@ Peter-ReinstateMonica Bkz. [Expr.call] / 4, "... Her parametrenin başlatılması ve imhası, çağrı fonksiyonu bağlamında gerçekleşir. ..."
Brian

8

Öyle güvenli değil :

Genel olarak, bir geçidin ömrü "geçirilerek" daha fazla uzatılamaz: geçicinin bağlı olduğu referanstan başlatılan ikinci bir referans, ömrünü etkilemez.


Öyleyse std::string s2 = foo();geçerli olduğunu düşünüyorsunuz (sonuçta açıkça referans geçmiyor)?
Peter - Monica'yı yeniden

1
@ Peter-ReinstateMonica yeni bir nesne inşa edileceği için güvenli biri. Cevabım sadece yaşam boyu genişleme ile ilgili. Diğer iki cevap zaten her şeyi kapsıyordu. Bende tekrar etmem.
Oblivion

5

Daha sonra dize ile ne yaptığınıza bağlıdır.

Sorunuz kodum doğru ise?o zaman evet öyle.

Kaynaktan [dcl.fct.default] / 2

[ Örnek : Beyan

void point(int = 3, int = 4);

int türünde sıfır, bir veya iki bağımsız değişkenle çağrılabilen bir işlevi bildirir. Aşağıdaki yollardan biriyle çağrılabilir:

point(1,2);  point(1);  point();

Son iki çağrı sırasıyla point(1,4)ve ile eşdeğerdir point(3,4). - son örnek ]

Yani kodunuz etkili bir şekilde aşağıdakilere eşdeğerdir:

const std::string& s1 = foo(std::string(""));
std::string s2 = foo(std::string(""));

Tüm kodlarınız doğru, ancak dönüş türünün bir referans olması nedeniyle bu durumların hiçbirinde referans ömür boyu uzantısı yok.

Geçici olan bir işlevi çağırdığınız için, döndürülen dizenin ömrü ifadeyi uzatmaz.

const std::string& s1 = foo(std::string("")); // okay

s1; // not okay, s1 is dead. s1 is the temporary.

Örneğin s2, doygunluğun bitiminden önce geçici olandan kopyaladığınız (veya taşıdığınız) ile örnek tamam. s3ile aynı soruna sahip s1.

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.