Thread overview
C++17 Sınıfın static inline üye verisine atama yaparken garip bir davranış oluşuyor.
Apr 10, 2020
İbrahim
Apr 11, 2020
kerdemdemir
Apr 11, 2020
İbrahim
Apr 11, 2020
İbrahim
April 10, 2020

Merhaba;
Soruya geçmeden önce C++17'den önce bir sınıfta static veri üyesi varsa ilk değeri sınıf dışında bir alanda atanmalı lakin C++17 ile birlikte inline ekleyerek static inline tür veriadi = değer diye sınıf içinde tanımlayabiliyoruz.

Implementation isminde bir soyut sınıfım var:

class Implementation
{
public:
 virtual void call() = 0;
};

Bu sınıftan kalıtım yapan Example ve AnotherExample diye iki sınıf şöyle:

class Example : public Implementation
{
public:
 void call() override
 {
   cout << "Example::call cagrildi!" << endl;
 }
};

class AnotherExample : public Implementation
{
public:
 void call() override
 {
   cout << "AnotherExample::call cagrildi!" << endl;
 }
};

Ve bu sınıfları programcının uygulaması için Implementer adında bir sınıf da şu şekilde:
(Bu sınıfın get_example üye fonksiyonuna geçilen flag eğer doğru ise example üye verisi, eğer yanlış ise another_example veri üyesi geri döndürülecek.)

class Implementer
{
private:
 static inline Implementation* example = unique_ptr<Example>(new Example).get();
 static inline Implementation* another_example = new AnotherExample; // make_unique<AnotherExample>().get();
public:
 static Implementation* get_example(bool flag)
 {
   if (flag)
     return example;
   else
     return another_example;
 }
};

Şöyle kullanalım:

Implementer::get_example(true)->call(); // example'ı kullanmalı.
Implementer::get_example(false)->call(); // Another_example'ı kullanmalı.

Çıktının

Example::call cagrildi!
AnotherExample::call cagrildi!

şeklinde olması gerekirken garip bir şekilde şöyle oluyor:

AnotherExample::call cagrildi!
AnotherExample::call cagrildi!

Şu iki satırda problem var:

static inline Implementation* example = unique_ptr<Example>(new Example).get();
static inline Implementation* another_example = new AnotherExample;

Eğer example'a new Example şeklinde bellek ayırırsam çıktı doğru oluyor ama yukarıdaki şekilde veya make_unique().get() şeklinde bellek ayırırsam çıktı iki tane "AnotherExample çağrıldı" oluyor. Eğer example'ı şöyle tanımlarsam

static inline unique_ptr<Example> example = make_unique<Example>();

doğru çıktı basıyor. Eğer iki tanımı da make_unique ile tanımlarsam program hata vermiyor, bir süre bekliyor ve sonra PRESS ENTER KEY'e düşüyor. Bu neden kaynaklanıyor olabilir? Problem çok garip geldi. Hata vermiyor, uyarı vermiyor ama garip bir şekilde altta tanımlı olan another_example'ın değeri yukarısında bulunan example'a da veriliyor.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

April 10, 2020

Benim bununla deneyimim yok ama böyle yeni olanaklarda derleyici veya standart hatası olması çok mümkün.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

April 11, 2020

Valla bende anlayamadım.

Biraz uğraştım örnek üstünde onun bağlantısın paylaşıyım belki anlatacak birisi çıkar.

https://coliru.stacked-crooked.com/view?id=33225546005f8299

Erdem

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

April 11, 2020

İşin ilginç tarafı eğer üye verinin türü soyut bir sınıftan kalıtılmamışsa bellek boşaltıldığı halde türün (yani sınıfın) veri üyelerine halâ daha ulaşabiliyoruz:

class ABC
{
public:
 ~ABC() {
     std::cout << "~ABC(), this=" << std::hex << this << std::dec << std::endl;
 }

 void call()
 {
   cout << "Called ABC::call function!" << std::endl;
 }
};

class Example
{
private:
 static inline ABC* data = unique_ptr<ABC>(new ABC).get();
public:
 static void print_data()
 {
   data->call();
 }
};

int main()
{
 Example::print_data();

 // Çıktı:
 /*
~ABC(), this=0xf4fc20
Called ABC::call function!
 */

 return 0;
}

Fakat ABC sınıfını soyut bir sınıftan türetirsek bellek boşaltıldığından dolayı üye fonksiyona erişemiyoruz:

class Abstract
{
public:
 virtual void call() = 0;
};

class ABC : public Abstract
{
public:
 ~ABC() {
     std::cout << "~ABC(), this=" << std::hex << this << std::dec << std::endl;
 }

 void call() override
 {
   cout << "Called ABC::call function!" << std::endl;
 }
};

class Example
{
private:
 static inline ABC* data = unique_ptr<ABC>(new ABC).get();
public:
 static void print_data()
 {
   data->call();
 }
};

int main()
{
   Example::print_data();

   // Çıktı:
   /*
~ABC(), this=0x18f3c20
bash: line 7: 17721 Segmentation fault      (core dumped) ./a.out
   */

   return 0;
}

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

April 11, 2020

@acehreli Evet yıkıcı fonksiyonlardan gelen çıktı nesnelerin atamadan hemen sonra silindiğini gösteriyor.
Alıntı:

>

Belki de ilk hata bile bununla ilgilidir çünkü ikinci türün static nesnesi geri verilmiş olan bellekte oluşturuluyordur.

Hocam burada garip olan durum atama yaptığımız nesnenin türü soyut bir sınıftan türetilmişse bu durum oluşuyor ama türetilmemişse bellek boşaldığı halde yine de ''Called ABC::call function!'' çıktısını alabiliyoruz. Yani kodun sağlıklı çalışıp çalışmamasını sağlayan şey nesne türünün soyut bir sınıftan türetilip türetilmemesi. Bu durum kafamı karıştırdı.
Not: Bu arada veri üyesinin static olup olmamasının da bir önemi yok. Static olmasa da aynı durumlar söz konusu.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

April 11, 2020

Programları ayrıntılı incelemedim ama sanırım bir hata görüyorum: Sağ taraftaki 'unique_ptr(new ABC).get()' ifadesinin ürettiği gösterge sonlanmış bir nesneyi göstermiyor mu? unique_ptr geçici bir nesne üretiyor, onun göstergesini get() ile alıyoruz. Atama işleminden sonra sağ taraftaki ifade sonlandırılırken geçini nesne göstergenin gösterdiği nesneyi sonlandırıyor.

Belki de ilk hata bile bununla ilgilidir çünkü ikinci türün static nesnesi geri verilmiş olan bellekte oluşturuluyordur.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

April 11, 2020

Eğer gösterdiğim konuyu hata olarak kabul edersek ondan sonrasını açıklamaya gerek olmamalı çünkü tanımsız davranışla (undefined behavior) karşı karşıyayız. Her tür gariplik olabilir.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]