c++error-handlingtemplate-classes

'std::logic_error' what(): basic_string::_M_construct null not valid


I have this cpp file and I have to write write a header for it, with an own template class. When I try to run the code it throws this 'std::logic_error' what(): basic_string::_M_construct null not valid error. It causes by the map_aligner<std::string, std::string> lsa; line but I don't really understand why and how to solve this issue.

The cpp:

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

The h:

#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

Solution

  • That error is caused by you trying to construct a string with a null pointer.

    Now look at the code that causes the error

    map_aligner<std::string, std::string> lsa;
    

    Both template parameters are strings.

    Now look at this code in map_aligner

        VALUE filler_ = (VALUE) NULL;
    

    VALUE is a std::string so this code is constructing a string from a null pointer, exactly as the error indicates.

    I don't know, but I guess you just want this

        VALUE filler_ = VALUE();
    

    It's a dangerous thing to try and construct an arbitrary type from NULL.