【问题标题】:C++ - std::map.insert() segmentation faultC++ - std::map.insert() 分段错误
【发布时间】:2013-11-22 13:01:47
【问题描述】:

当我尝试插入我的地图时遇到分段错误。

函数看起来像这样:

void add(std::string id, std::string name)
{
Asset asset(nullptr, false, name);
mAssets.insert(std::make_pair<std::string, Asset>(id,asset)); <-- This line gives segfault
}

mAssets 被简单地声明

std::map<assetID, Asset> mAssets;

资产类(草率)声明如下:

class Asset
{
public:
   Asset(T* a, bool l, std::string f) : asset(a), loaded(l), filename(f)
    {
    }
  Asset(const Asset& copy) 
{
  loaded   = copy.loaded;
  filename = copy.filename;
  asset    = new T();
  *asset   = *copy.asset;
}
  ~Asset()
{
  delete asset;
}
  Asset& operator=(const Asset& other)
{
  Asset temp(other);
  loaded = temp.loaded;
  filename = temp.filename;
  std::swap(asset,temp.asset);
  return *this;
}

  T*          asset;
  bool        loaded;
  std::string filename;
};

【问题讨论】:

  • 你的assetId键类是什么?
  • assetID 是一个类型化的 std::string
  • 通常是为了让代码更具可读性(至少对我而言),我更喜欢:mAssets[id] = asset;
  • 您有时会将 nullptr 放入资产中(例如,在崩溃的函数中)-考虑当 *asset = *copy.asset 运行时会发生什么......您应该在复制构造函数中处理 nullptr 情况.

标签: c++ c++11 dictionary insert segmentation-fault


【解决方案1】:

您的问题出在您的复制构造函数中:

  asset    = new T();
  *asset   = *copy.asset;

我会留给你找出原因......

【讨论】:

  • 那么您的问题出在其他地方(至少不在您提供的代码中...)
  • 我已将范围缩小到该特定行,代码似乎可以在运行 ubuntu 的笔记本电脑上运行,但在这台 Solaris 计算机上却不行。..
  • 然后运行调试器并查看失败的确切位置 - 它应该比等待我们猜测花费的时间更少(?)
  • 抱歉这个愚蠢的问题,但我该如何运行调试器?这是我第一次在这个平台上开发,我使用 emacs 和 gcc
  • 检查您的平台是否安装了gdb,然后在提示符处运行gdb &lt;name of binary&gt;,然后运行run。至于如何使用gdb(GNU Debugger),使用你喜欢的搜索引擎快速教程,只需要10分钟左右...
【解决方案2】:

在您的复制构造函数中,您正在取消引用一个空指针:

*asset = *copy.asset

来自

Asset asset(nullptr, false, name);

验证您的指针分配并避免取消引用空指针:

Asset(const Asset& copy) 
{
    loaded   = copy.loaded;
    filename = copy.filename;
    if (copy.asset)
    {
        asset    = new T();   // better may be asset = new T(copy)
        *asset   = *copy.asset;
    }
    else
    {
        asset = nullptr
    } 
}

【讨论】:

  • 这仍然无法修复崩溃
  • 您是否尝试在销毁时检查指针删除????在某些平台上,例如 Linux 和大多数 unix,您不能删除空指针。查看所有取消引用的指针
  • 修复了这个问题,仍然没有运气。顺便说一句,我正在运行 solaris
  • @TioPepe,我不确定那句话,AFAIK,标准说在nullptr 上调用delete 应该最终什么都不做......
【解决方案3】:

*asset = *copy.asset; //你应该检查asset是否为NULL然后检查asset

这就是您的代码的工作方式:

#include <iostream>
#include <map>

using namespace std;

template<class T>
class Asset
{
  public:
    Asset(T* a, bool l, std::string f) : asset(a), loaded(l), filename(f)
  {
  }
    Asset(const Asset& copy) 
    {
      cout<<"copy"<<endl;
      loaded   = copy.loaded;
      filename = copy.filename;
      asset    = new T();
      if(&copy != NULL)
      {
      if(copy.asset != NULL)
        *asset   = *(copy.asset);
      }
    }
    ~Asset()
    {
      delete asset;
    }
    Asset& operator=(const Asset& other)
    {
      Asset temp(other);
      loaded = temp.loaded;
      filename = temp.filename;
      std::swap(asset,temp.asset);
      return *this;
    }

    T*          asset;
    bool        loaded;
    std::string filename;
};

std::map <string,Asset<int> > mAssets;

void add(std::string id, std::string name)
{
  Asset<int> asset(NULL, false, name);
  mAssets.insert(std::make_pair<std::string, Asset<int> >(id,asset)); //<-- This line gives segfault
}


int main()
{
  add("1","hi");
  cout<<"run"<<endl;

}

【讨论】:

  • 这样做的目的是什么-> if(&amp;copy != NULL)
  • if(&copy != NULL) 可以被删除,但在复制数据之前应检查指针是否指向有效数据,以确保复制构造函数正常工作。
猜你喜欢
  • 2014-12-28
  • 2013-04-28
  • 1970-01-01
  • 2016-07-16
  • 1970-01-01
  • 1970-01-01
  • 2012-02-10
  • 1970-01-01
  • 2017-03-26
相关资源
最近更新 更多