在指向向量的智能指针上使用 push_back() 时出现运行时错误

Posted

技术标签:

【中文标题】在指向向量的智能指针上使用 push_back() 时出现运行时错误【英文标题】:Runtime error when using push_back() on smart pointer to vector 【发布时间】:2019-04-18 18:04:33 【问题描述】:

我正在尝试通过取消引用智能指针来填充向量。在运行期间,程序在用于输入变量输入的第一个“for”循环的一次迭代后崩溃。

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;

使用 VS 调试器时,它显示抛出异常(抛出异常:读取访问冲突。 std::_Vector_alloc > >::_Myend(...) 在向量文件中返回 0xC.),特别是第 1793 - 1795 行:

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

这个错误的原因是什么?

【问题讨论】:

嗯,data 指的是什么??? 看起来您从未为智能指针分配对象。 取消引用 nullptr(也适用于智能指针)是未定义行为。 @alterigel 是的,这是错误,谢谢 【参考方案1】:

默认构造的shared_ptr 不指向任何有效的东西。来自https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr:

构造一个没有托管对象的shared_ptr,即空shared_ptr

您需要对其进行初始化,使其指向它管理的有效对象,然后才能使用底层指针。例如,将构造函数更改为:

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

   ...

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

   ...

【讨论】:

使用 new 初始化智能指针会导致两倍的分配(~2x 慢)。使用std::make_shared 为对象和标签一起分配空间。 @CruzJean,请澄清您所说的两次分配是什么意思。您当然不是指 std::vector 分配的两倍,对吗? @RSahu 通过两次分配,他的意思是一个用于对象,一个用于引用计数器。我看不出有任何理由在这里使用new 而不是make_shared 是的,这是个愚蠢的错误,谢谢。使用make_shared 而不是new 实现。【参考方案2】:

你需要在使用之前为data分配内存:

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

【讨论】:

感谢您的帮助!【参考方案3】:

您从未初始化 ptr。下面演示default initializers for member variables和member initializer lists的使用。

您可以轻松地将 ptr 初始化添加到初始化列表中,但因为它不依赖于任何构造函数参数。最好以下面的方式声明它的构造,以避免在创建其他构造函数时出现复制/粘贴错误。

#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;                                                                    
  

输出:

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

【讨论】:

以上是关于在指向向量的智能指针上使用 push_back() 时出现运行时错误的主要内容,如果未能解决你的问题,请参考以下文章

push_back 指向指针向量的指针

如何创建指向向量的指针向量

C ++如何使用指向向量指针的指针

指向向量的 C++ 指针

带有智能指针的 C++11 向量

用向量 c++ 中的指针成员初始化对象