user2836797
user2836797

Reputation:

unique_ptr Segmentation fault when calling operator[]() on pointed to object

I am struggling to wrap my head around a nasty runtime error. It's a bit of code to post, but I hope it's not too much to read and too little to diagnose the issue. For some reason the unique_ptr is blowing up when I deference it and use the operator function call.

class Dataset
{
  private:
    std::unique_ptr<File> file;
    std::unique_ptr<File> & getFile() throw () { return file; }

    std::unique_ptr<Properties> properties;
    std::unique_ptr<Properties> & getProperties() throw () 
    { 
      return properties; 
    }

  ...
}

class Properties
{
  private:
    std::map<const std::string, Property> container;

  public:
    Property & operator[](const std::string & s) {
      try
      {
        return container.at(s);
      }
      catch (std::out_of_range & e)
      {
        std::stringstream ss;
        ss << "Key \"" << s << "\" does not exist in collection in 
          file " << __FILE__ << " at line " << __LINE__;
        throw Exception::KeyNotFound(ss.str(), __FILE__, __LINE__);
      }
    }
  ...
}

class FrameCollection
{
  private:
    Dataset & dataset;
  public:
    FrameCollection();
  ...
}

FrameCollection::FrameCollection()
{
  Property property (
    dataset.getProperties()->operator[](PROPERTY_MAX_FRAMES)
  );
...
}

The unique pointer blows up in FrameCollection():

Thread [1] 14303 [core: 10] (Suspended : Signal : SIGSEGV:Segmentation fault) std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::_M_begin() at stl_tree.h:502 0x7ffff7ba9d72
std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::lower_bound() at stl_tree.h:879 0x7ffff7bbbd4e
std::map, std::allocator > >::lower_bound() at stl_map.h:864 0x7ffff7bbba39
std::map, std::allocator > >::at() at stl_map.h:503 0x7ffff7bbb762 bmd2::PropertyCollection::operator at PersistentObject.cpp:140 0x7ffff7bb9137
bmd2::FrameCollection::FrameCollection() at FrameCollection.cpp:16 0x7ffff7bb5425
bmd2::Dataset::Dataset() at Dataset.cpp:68 0x7ffff7ba61f9
__gnu_cxx::new_allocator::construct >() at new_allocator.h:120 0x7ffff7ba3b67
std::allocator_traits >::_S_construct >() at alloc_traits.h:254 0x7ffff7ba3977
std::allocator_traits >::construct >() at alloc_traits.h:393 0x7ffff7ba37b7
<...more frames...>

Upvotes: 1

Views: 1626

Answers (1)

clcto
clcto

Reputation: 9648

The issue is in your FrameCollection class. You define a reference but never initialize it in the constructor.

class FrameCollection
{
private:
    Dataset & dataset;
public:
    FrameCollection();
    // ...
}

FrameCollection::FrameCollection()
{
   Property property (
      dataset.getProperties()->operator[](PROPERTY_MAX_FRAMES)
   );
   //...
}

When you have a reference variable in a class, the constructor should take a reference and initiate the member in the initialization list:

class FrameCollection
{
private:
    Dataset & dataset;
public:
    FrameCollection( Dataset& );
    // ...
}

FrameCollection::FrameCollection( Dataset& d ) :
    dataset( d )
{
   Property property (
      dataset.getProperties()->operator[](PROPERTY_MAX_FRAMES)
   );
   //...
}

Upvotes: 1

Related Questions