SORU
7 Ocak 2014, Salı


Neden Çınlama ve VS2013 ayracı-başlatıldı varsayılan bağımsız hareket eden, ama 4.8 veya 4.9 GCC kabul etmez?

Başlıktan da anlaşılacağı gibi, gcc 4.8 ve 4.9 gcc ile derleme sonra koştu zaman o uygulamaları ile, ama çekirdek üzerine döker derler kısa bir demo program var:

Herhangi bir fikir neden?

#include <unordered_map>

struct Foo : std::unordered_map<int,int> {
    using std::unordered_map<int, int>::unordered_map;
    // ~Foo() = default; // adding this allows it to work
};

struct Bar {
    Bar(Foo f = {}) : _f(std::move(f)) {}
    // using any of the following constructors fixes the problem:
    // Bar(Foo f = Foo()) : _f(std::move(f)) {}
    // Bar(Foo f = {}) : _f(f) {}

    Foo _f;
};

int main() {
    Bar b;

    // the following code works as expected
    // Foo f1 = {};
    // Foo f2 = std::move(f1);
}

Derleme ayarları:

g   --std=c  11 main.cpp

İşte GDB bir geri iz:

#0  0x00007fff95d50866 in __pthread_kill ()
#1  0x00007fff90ba435c in pthread_kill ()
#2  0x00007fff8e7d1bba in abort ()
#3  0x00007fff9682e093 in free ()
#4  0x0000000100002108 in __gnu_cxx::new_allocator<std::__detail::_Hash_node_base*>::deallocate ()
#5  0x0000000100001e7d in std::allocator_traits<std::allocator<std::__detail::_Hash_node_base*> >::deallocate ()
#6  0x0000000100001adc in std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<int const, int>, false> > >::_M_deallocate_buckets ()
#7  0x000000010000182e in std::_Hashtable<int, std::pair<int const, int>, std::allocator<std::pair<int const, int> >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::_M_deallocate_buckets ()
#8  0x000000010000155a in std::_Hashtable<int, std::pair<int const, int>, std::allocator<std::pair<int const, int> >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::~_Hashtable ()
#9  0x000000010000135c in std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<int const, int> > >::~unordered_map ()
#10 0x00000001000013de in Foo::~Foo ()
#11 0x0000000100001482 in Bar::~Bar ()
#12 0x0000000100001294 in main ()

*** error for object 0x1003038a0: pointer being freed was not allocated ***

CEVAP
15 Ocak 2014, ÇARŞAMBA


Güncelleme

fix for the problem has been checked in bir görünür.


İlginç bir soru. Kesinlikle = {} late addition to the standard hangi başlatılmış varsayılan argümanlar, nasıl işlediği ile ilgili bir hata gibi görünüyor. Sorun std::unordered_map<int,int> yerine oldukça basit bir sınıf ile yeniden:

#include <utility>

struct PtrClass
{
    int *p = nullptr;

    PtrClass()
    {
        p = new int;
    }

    PtrClass(PtrClass&& rhs) : p(rhs.p)
    {
        rhs.p = nullptr;
    }

    ~PtrClass()
    {
        delete p;
    }
};

void DefArgFunc(PtrClass x = {})
{
    PtrClass x2{std::move(x)};
}

int main()
{
    DefArgFunc();
    return 0;
}

27 ** aynı sorun görüntüler:

*** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0000000001aa9010 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6( 0x7eb96)[0x7fc2cd196b96]
./a.out[0x400721]
./a.out[0x4006ac]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main 0xed)[0x7fc2cd13976d]
./a.out[0x400559]
======= Memory map: ========
bash: line 7:  2916 Aborted                 (core dumped) ./a.out

Kazma biraz daha derin, GCC bu sözdizimini kullandığınızda: fazladan bir nesne sadece bir kez ve her kurucu yıkıcı çağrıları olsa da) oluşturmak gibi görünüyor

#include <utility>
#include <iostream>

struct SimpleClass
{    
    SimpleClass()
    {
        std::cout << "In constructor: " << this << std::endl;
    }

    ~SimpleClass()
    {
        std::cout  << "In destructor: " << this << std::endl;
    }
};

void DefArgFunc(SimpleClass x = {})
{
        std::cout << "In DefArgFunc: " << &x << std::endl;
}

int main()
{
    DefArgFunc();
    return 0;
}

Output:

In constructor: 0x7fffbf873ebf
In DefArgFunc: 0x7fffbf873ea0
In destructor: 0x7fffbf873ebf

SimpleClass x = SimpleClass{} SimpleClass x = {} varsayılan bağımsız değişken değiştirme üretir

In constructor: 0x7fffdde483bf
In DefArgFunc: 0x7fffdde483bf
In destructor: 0x7fffdde483bf

beklendiği gibi.

Oluyormuş gibi görünüyor bir nesne oluşturulduğunda, varsayılan oluşturucu denir, ve sonra bir şey memcpy benzer yapılır. "Hayalet nesne" hareket yapıcı ve modifiye geçti. bu Ancak, yıkıcı, şimdi hareket edilmiş bir nesne ile bazı işaretçi paylaştığı, orijinal adı verilir, değiştirilmemiş, nesne,. Her ikisi de sonunda özgür, soruna neden deneyin.

Sorun çözülmezse fark dört değişiklikleri yukarıdaki açıklama verilen anlam:

// 1
// adding the destructor inhibits the compiler generated move constructor for Foo,
// so the copy constructor is called instead and the moved-to object gets a new
// pointer that it doesn't share with the "ghost object", hence no double-free
~Foo() = default;

// 2
// No  `= {}` default argument, GCC bug isn't triggered, no "ghost object"
Bar(Foo f = Foo()) : _f(std::move(f)) {}

// 3
// The copy constructor is called instead of the move constructor
Bar(Foo f = {}) : _f(f) {}

// 4
// No  `= {}` default argument, GCC bug isn't triggered, no "ghost object"
Foo f1 = {};
Foo f2 = std::move(f1);

Oluşturucu için bağımsız değişken (Bar b(Foo{});) geçirmeden yerine varsayılan argümanı kullanarak da sorunu çözer.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • BigDawsTv

    BigDawsTv

    20 HAZİRAN 2012
  • LiteralMSPaint

    LiteralMSPai

    27 EKİM 2010
  • MyTiredBones

    MyTiredBones

    2 Temmuz 2013