简体   繁体   中英

Runtime error when using push_back() on smart pointer to vector

I am trying to fill a vector, by dereferencing a smart-pointer. During runtime the program crashes after one iteration of the first "for" loop used for entering the variable input.

using namespace std;

class Measurement
{
protected:
    int sample_size;
    string label;
    shared_ptr <vector<double>> data;
public:
    // parameterised constructor
    Measurement(string pLabel, int pSample_size)
    {
        label = pLabel;
        sample_size = pSample_size;
        cout << "Please input your dataset one entry at a time:" << endl;
        for (int i = 0; i < sample_size; i++)
        {
            double input;
            cin >> input;
            data->push_back(input); // NOT WORKING???
        }
    }
};

int main()
{
    Measurement A("xData", 5);
    return 0;
}

When using the VS debugger it shows that an exception is thrown (Exception thrown: read access violation. std::_Vector_alloc > >::_Myend(...) returned 0xC.) in the vector file, specifically lines 1793 - 1795:

bool _Has_unused_capacity() const _NOEXCEPT
    {   // micro-optimization for capacity() != size()
    return (this->_Myend() != this->_Mylast());

What is the cause of this error?

A default constructed shared_ptr does not point to anything valid. From https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr :

Constructs a shared_ptr with no managed object, ie empty shared_ptr .

You need to initialize it such that it points to valid object that it manages before you can use the underlying pointer. For example, change the constructor to:

Measurement(string pLabel, int pSample_size) : data(new std::vector<double>()) 
{
   ...
}

or

Measurement(string pLabel, int pSample_size) : data(std::make_shared<std::vector<double>>()) 
{
   ...
}

You need to allocate memory for data before use it:

Measurement(string pLabel, int pSample_size) {
   ...
   data = std::make_shared<vector<double>>();
   ...
}

You never initialized the ptr. Below demonstrates the use of default initializers for member variables and member initializer lists .

You could easily add the ptr initialization to the initialization list, but since it doesn't depend on any constructor arguments. It's better to declare it's construction in the manner below to avoid a copy/paste error when creating additional constructors.

#include <iostream>                                                              
#include <vector>                                                                
#include <memory>                                                                

using namespace std;                                                             

class Measurement {                                                              
  protected:                                                                     
    int                        sample_size_;                                     
    string                     label_;                                           
    shared_ptr<vector<double>> data_{make_shared<vector<double>>()};             

  public:                                                                        
    // parameterised constructor                                                 
    Measurement( string pLabel, int pSample_size )                               
      : sample_size_( pSample_size )                                             
      , label_( pLabel )                                                         
    {                                                                            
        cout << "Please input your dataset one entry at a time:" << endl;        
        for ( int i = 0; i < sample_size_; i++ ) {                               
            double input;                                                        
            cin >> input;                                                        
            data_->push_back( input ); // NOT WORKING???                         
        }                                                                        
    }                                                                            

    friend ostream& operator<<( ostream& os, Measurement const& op1 )            
    {                                                                            
        for ( auto& v : *op1.data_ )                                             
            os << v << " ";                                                      
        return os;                                                               
    }                                                                            
};                                                                               

int main()                                                                       
{                                                                                
    Measurement A( "xData", 5 );                                                 
    cout << A << endl;                                                           
    return 0;                                                                    
}  

Output:

g++     example.cpp   -o example
Please input your dataset one entry at a time:
1
2
3
4
5
1 2 3 4 5 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM