You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实例化map_aligner<string,string>触发std::logic_error错误排查

C++模板类初始化引发std::logic_error错误排查与修复

我编写了一个自定义模板类头文件mapalign.h,用于对齐多个std::map的键值对。但运行代码时触发错误:'std::logic_error' what(): basic_string::_M_construct null not valid,定位到错误由map_aligner<std::string, std::string> lsa;这行代码引发,不清楚错误原因及解决方法。


源文件代码

#include <iostream>
#include "mapalign.h"
#include <string>
#include <algorithm>
#include <map>
#include "mapalign.h"

struct string_size_less
{
  bool operator()( const std::string& a,
                   const std::string& b ) const
  {
    return a.size() < b.size();
  }
};

const int max = 1000;

bool check()
{
  std::map<std::string, int> sma;
  std::map<std::string, int> smb;
  std::map<std::string, int> smc;

  map_aligner<std::string, int> sa;
  sa.add( sma );
  sa.add( smb );
  sa.add( smc );

  sma[ "C++" ] = 1;
  smb[ "Ada" ] = 2;
  smc[ "C" ] = 3;
  smc[ "Python" ] = 4;
  smc[ "Ada"] = 5;

  sa.align();

  std::map<int, double> ima;
  std::map<int, double> imb;
  for( int i = 0; i < max; ++i )
  {
    if ( 0 == i % 2 )
    {
      ima[ i ] = max - i;
    }
    else
    {
      imb[ i ] = max;
    }
  }

  map_aligner<int, double> ia;
  ia.add( ima );
  ia.add( imb );

  ia.align();

  if ( ( 4 != sma.size() && 1 != imb.count( 0 )) || max * 1U != ima.size() ||
       1 != smc.count( "C++" ) || "Ada" != sma.begin()->first ||
       0 != sma.begin()->second ||  4 != smc.size() ||
       1 != smb.count( "Python" ) || 0 != imb.begin()->first ||
       0.8 <= imb.begin()->second || 1 != imb.count( max / 2 ) )
  {
    return false;
  }

  sma[ "Pascal" ] = 5;
  sa.set_filler( max );
  sa.align();

  std::map<std::string, std::string> langsa;
  langsa[ "C++" ] = "<3";
  langsa[ "Python" ] = ":|";
  std::map<std::string, std::string> langsb;
  langsb[ "Brainfuck" ] = ":S";
  langsb[ "Python" ] = ":/";
  langsb[ "C" ] = ":)";

  map_aligner<std::string, std::string> lsa;
  lsa.add( langsa );
  lsa.add( langsb );

  lsa.align();
  lsa.erase( "Python" );

  if ( 0 != langsa.count( "Python" ) || max != smc[ "Pascal" ] ||
       !langsa.begin()->second.empty() || max != smb[ "Pascal" ] ||
       2 * 1U != langsb.begin()->second.size() ||
       0 != langsb.count( "Python" ) || 1 != langsb.count( "C++" ) )
  {
    return false;
  }

  std::map<std::string, std::string, string_size_less> lma;
  std::map<std::string, std::string, string_size_less> lmb;
  std::map<std::string, std::string, string_size_less> lmc;

  lma[ "C++" ] = ":D";
  lmb[ "Eiffel" ] = ":P";
  lmc[ "C" ] = "8-)";
  lmc[ "Ada" ] = "!";

  map_aligner<std::string, std::string, string_size_less> ls;
  ls.add( lma );
  (ls += lmb) += lmc;

  ls.align();

  std::cout << (3 == ls.count()) << (1 == lmc.count( "Ada" )) <<
       (3 * 1U == lmb.size()) << (1 == lma.count( "Python" )) <<
       (2 == lsa.count()) << (2 == ia.count()) ;

  return ( 3 == ls.count() && 1 == lmc.count( "Ada" ) &&
       3 * 1U == lmb.size() && 1 == lma.count( "Python" ) &&
       2 == lsa.count() && 2 == ia.count() );
}

int main()
{
  std::cout
    << "Your solution is "
    << (check() ? "" : "not ")
    << "ready for submission."
    << std::endl;
}

头文件代码

#ifndef MAPALIGN_H
#define MAPALIGN_H

#include <vector>
#include <map>
#include <typeinfo>

template<typename KEY, typename VALUE, typename COMPARE = std::less<KEY>>
class map_aligner{

    public:
            typedef typename std::map<KEY, VALUE, COMPARE>::size_type size_type;

            map_aligner() {}

            void add(std::map<KEY, VALUE, COMPARE>& m) {
                maps_.push_back(&m);
            }

            map_aligner<KEY, VALUE, COMPARE> operator+=(std::map<KEY, VALUE, COMPARE>& m){
                return maps_.push_back(&m);
            }

            size_type count() const {
                return maps_.size();
            }

            void align(){
                for(int i = 0; i != (int)maps_.size(); i++ ){
                    std::map<KEY, VALUE>* first_map = maps_.at(i);
                    for(typename std::map<KEY, VALUE>::iterator j = first_map->begin(); j !=first_map->end(); j++ ){
                        for(int h = 0; h != (int)maps_.size(); h++ ){
                            std::map<KEY, VALUE>* second_map = maps_.at(h);
                            if(first_map != second_map && notContainsPair(second_map, j)){
                                second_map->insert(std::make_pair(j->first, filler_));
                            }
                        }
                    }
                }
            }

            bool notContainsPair(std::map<KEY, VALUE>* map,typename std::map<KEY, VALUE>::iterator it){
                for(typename std::map<KEY, VALUE>::iterator g = map->begin(); g != map->end(); g++ ){
                    if(it->first != g->first){
                        return true;
                    }
                }
                return false;
            }

            void set_filler(VALUE filler){
                filler_ = filler;
            }

            void erase(KEY key){
                for(int h = 0; h != (int)maps_.size(); h++ ){
                    std::map<KEY, VALUE>* map = maps_.at(h);
                    typename std::map<KEY, VALUE>::iterator it;
                    if(typeid(it->first) != typeid(it->first)){
                        map->erase(key);
                    }
                }
            }

    private:
        std::vector<std::map<KEY, VALUE, COMPARE>*> maps_; 
        VALUE filler_ = (VALUE) NULL;
};

#endif

错误原因

  • filler_初始化非法:头文件中VALUE filler_ = (VALUE) NULL;,当VALUE为std::string时,将NULL(本质是0)强制转换为std::string,会触发字符串构造函数尝试从空指针创建对象,这是未定义行为,直接抛出std::logic_error。
  • notContainsPair逻辑完全错误:该函数遍历map时,只要遇到一个键不等于目标键就返回true,实际应该是遍历完所有键都不存在才返回true,当前逻辑会导致错误插入大量无效键值对。
  • operator+=返回值错误:push_back是void类型,无法返回map_aligner对象,会导致编译报错。
  • erase函数逻辑无效:if(typeid(it->first) != typeid(it->first))永远为false,erase操作从未执行。

修复方案

1. 修正filler_初始化

将类内的VALUE filler_ = (VALUE) NULL;移除,改为在构造函数中用值初始化语法生成合法默认值:

map_aligner() : filler_(VALUE{}) {}

这样对于std::string会初始化为空字符串,数值类型会初始化为0,符合各类型的合法默认值规则。

2. 修复notContainsPair函数

直接使用map::find方法判断键是否存在,更高效且逻辑正确:

bool notContainsPair(std::map<KEY, VALUE, COMPARE>* map, typename std::map<KEY, VALUE, COMPARE>::iterator it){
    return map->find(it->first) == map->end();
}

3. 修正operator+=返回值

改为返回*this,支持链式调用:

map_aligner<KEY, VALUE, COMPARE>& operator+=(std::map<KEY, VALUE, COMPARE>& m){
    maps_.push_back(&m);
    return *this;
}

4. 修复erase函数

移除无效的typeid判断,直接执行erase:

void erase(KEY key){
    for(auto* map : maps_){
        map->erase(key);
    }
}

5. 修正align函数的类型匹配问题

align函数中统一使用std::map<KEY, VALUE, COMPARE>类型,同时改用范围for循环简化代码:

void align(){
    for(auto* first_map : maps_){
        for(const auto& pair : *first_map){
            for(auto* second_map : maps_){
                if(first_map != second_map && second_map->find(pair.first) == second_map->end()){
                    second_map->insert(std::make_pair(pair.first, filler_));
                }
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者programmerGirl82

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 11:55:18