c++ - Do I need to set my destructor methods when I am using shared pointers? -


i tried finding answer didn't see 1 particular problem. using shared pointers ternary search tree (to used predictive text algorithm) , running problems using shared pointers.

i've been away c++ 5 years, , let me tell you, java not learn pointers. i've had relearn pointer material learned in school 5-6 years ago on past couple of days, , have managed destroy code.

here of code have:

// ternarysearchtree.cc  #include "stdafx.h" #include "ternary_search_tree.h"  //constructor ternarysearchtree::ternarysearchtree() {   num_nodes_ = 0;   size_in_memory_ = 0;   root_node_ = nullptr; }  ternarysearchtree::ternarysearchtree(const ternarysearchtree& other) {   num_nodes_ = other.num_nodes_;   size_in_memory_ = other.size_in_memory_;    ternarysearchtreenode node;   node = *other.root_node_;   root_node_.reset(&node); }  //destructor ternarysearchtree::~ternarysearchtree() {  }  //operators ternarysearchtree& ternarysearchtree::operator=(const ternarysearchtree& other) {    //todo: swap idiom - create copy of node swap new 1   //do first provide exception safety   ternarysearchtreenode node;   node = *other.root_node_;    root_node_.reset(&node);   num_nodes_ = other.num_nodes_;   size_in_memory_ = other.size_in_memory_;    return *this; }  //convert string c-style string std::vector<char> ternarysearchtree::convertstringtocstring(std::string str) {    std::vector<char> wordcharacters (str.begin(), str.end());   //remove newlines or tabs   if (wordcharacters.back() == '\n' || wordcharacters.back() == '\t') {     wordcharacters.pop_back();   }   wordcharacters.push_back('\0');   return wordcharacters; }  //insert node ternarysearchtreenode ternarysearchtree::insertnode(ternarysearchtreenode &currentnode,                                                      char character,                                                     nodeposition position,                                                     bool isroot) {    ternarysearchtreenode newnode;   newnode.set_character(character);    if (!isroot) {     switch (position) {     case node_pos_left:       currentnode.set_left_node(newnode);       break;     case node_pos_centre:       currentnode.set_centre_node(newnode);       break;     case node_pos_right:       currentnode.set_right_node(newnode);       break;     default:       break;     }   }    return newnode; }  //insert word void ternarysearchtree::insertword(std::string word) {    std::vector<char> characters = convertstringtocstring(word);   std::shared_ptr<ternarysearchtreenode> currentnode = 0;   bool isfirstcharacter = true;    //add each character node while traversing   //base case there no root node   if (!root_node_) {      for(std::vector<char>::iterator = characters.begin(); != characters.end(); ++it) {        if (*it != '\0') {                 //if first character         //root_node_ equal address of new node         if (isfirstcharacter) {           std::cout << "hihi";           ternarysearchtreenode node = insertnode(*currentnode, *it, node_pos_centre, true);           root_node_.reset(&node);           currentnode.reset(&node);           isfirstcharacter = false;          } else {           ternarysearchtreenode node = insertnode(*currentnode, *it, node_pos_centre, false);           std::cout << std::endl << node.get_character();           currentnode.reset(&node);         }       }     }     //if not base case, need compare each character   } else {     currentnode = root_node_;     for(std::vector<char>::iterator = characters.begin(); != characters.end(); ++it) {       if (*it != '\0') {         currentnode.reset(&setnextnode(*currentnode, *it, *std::next(it, 1)));       } else {         currentnode->set_end_of_word(true);       }     }   } }  //recursive function obtaining/adding next node when inserting word ternarysearchtreenode ternarysearchtree::setnextnode(ternarysearchtreenode &currentnode, const char currentchar, const char nextchar) {    //if characters match   if (currentchar == currentnode.get_character()) {      //if centre node exists     if (currentnode.get_centre_node()) {       return *(currentnode.get_centre_node());        //otherwise, create new node , recall method on node     } else {        //if not end of word, make new node next letter       if (nextchar != '\0') {         return insertnode(currentnode, nextchar, node_pos_centre, false);        } else {         return currentnode;       }     }     //if less, follow node on left   } else if (currentchar < currentnode.get_character()) {      //if left node exists, recursive call     if (currentnode.get_left_node()) {       return setnextnode(*(currentnode.get_left_node()), currentchar, nextchar);        //otherwise, create new node , recall method on node     } else {       return setnextnode(insertnode(currentnode, currentchar, node_pos_left, false), currentchar, nextchar);     }     //otherwise bigger, take right path   } else {      //if right node exists, recursive call     if (currentnode.get_right_node()) {       return setnextnode(*(currentnode.get_right_node()), currentchar, nextchar);        //otherwise, create new node , recall method on node     } else {       return setnextnode(insertnode(currentnode, currentchar, node_pos_right, false), currentchar, nextchar);     }   } }  //populate tst word list/file void ternarysearchtree::populatetreefromtextfile(std::string filename) {    std::ifstream file;   std::string line;   file.open(filename);    if (file.is_open()) {     //assume text file has 1 word per line     while (std::getline(file, line)) {       insertword(line);     }        } }  //search bool ternarysearchtree::searchforword(std::string word) {   return false; }  int _tmain(int argc, _tchar* argv[]) {    //test   ternarysearchtree tst;   //open file   tst.populatetreefromtextfile("simple.txt");    //start @ root , follow paths  std::cout << tst.get_root_node();     /**std::vector<char> vec;   vec.push_back('a');   vec.push_back('c');   std::vector<char>::iterator = vec.begin();   std::cout << *std::next(vec.begin(), 1);   std::cout << (*it < 'c');   it++;   std::cout << *std::next(it, 0);   std::cout <<  (*it < 'c');   **/   return 0; } 

and nodes:

/*tst node methods */ #include <iostream> #include "ternary_search_tree_node.h"  /** add copy constructor*/ //constructors ternarysearchtreenode::ternarysearchtreenode() {    character_ = '\0';   end_of_word_ = false;   left_node_ = nullptr;   centre_node_ = nullptr;   right_node_ = nullptr; }  ternarysearchtreenode::ternarysearchtreenode(const ternarysearchtreenode& other) {    character_ = other.character_;   end_of_word_ = other.end_of_word_;    ternarysearchtreenode leftnode;   leftnode = *other.left_node_;   left_node_.reset(&leftnode);    ternarysearchtreenode centrenode;   centrenode = *other.centre_node_;   centre_node_.reset(&centrenode);    ternarysearchtreenode rightnode;   rightnode = *other.right_node_;   right_node_.reset(&rightnode); }  ternarysearchtreenode::ternarysearchtreenode(char character, bool end_of_word,                                              ternarysearchtreenode left_node,                                               ternarysearchtreenode centre_node,                                               ternarysearchtreenode right_node) {    character_ = character;   end_of_word_ = end_of_word;   left_node_.reset(&left_node);   centre_node_.reset(&centre_node);   right_node_.reset(&right_node); }  //destructor ternarysearchtreenode::~ternarysearchtreenode() {    left_node_.reset();   centre_node_.reset();   right_node_.reset();  }  //operators ternarysearchtreenode& ternarysearchtreenode::operator=(const ternarysearchtreenode& other) {    if (&other) {     ternarysearchtreenode leftnode;     leftnode = *other.left_node_;     ternarysearchtreenode centrenode;     centrenode = *other.centre_node_;     ternarysearchtreenode rightnode;     rightnode = *other.right_node_;      left_node_.reset(&leftnode);     centre_node_.reset(&centrenode);     right_node_.reset(&rightnode);      character_ = other.character_;     end_of_word_ = other.end_of_word_;   }    return *this; }  //printing std::ostream& operator<<(std::ostream& os, const ternarysearchtreenode& obj) {   // write obj stream   char c = obj.get_character();   bool b = obj.is_end_of_word();    os << c << "\t end of word: " << b;   return os; } 

when run in debug mode (visual studios), able set root node, when goes input second node, crashes trying delete "stuff" when currentnode calls .reset(&node) within else statement of function insertword. doing wrong in copy constructors or operator= methods, or destructors? cout line above print correct letter, looks node getting created properly.

the debug call stack shows:

ternarysearchtree.exe!std::_ref_count_base::_decref() line 118 c++ ternarysearchtree.exe!std::_ptr_base::_decref() line 347 c++ ternarysearchtree.exe!std::shared_ptr::~shared_ptr() line 624 c++ ternarysearchtree.exe!std::shared_ptr::reset() line 649 c++ ternarysearchtree.exe!ternarysearchtreenode::~ternarysearchtreenode() line 50 c++ ternarysearchtree.exe!ternarysearchtreenode::`scalar deleting destructor'(unsigned int) c++ ternarysearchtree.exe!std::_ref_count::_destroy() line 161 c++ ternarysearchtree.exe!std::_ref_count_base::_decref() line 120 c++ ternarysearchtree.exe!std::_ptr_base::_decref() line 347 c++ ternarysearchtree.exe!std::shared_ptr::~shared_ptr() line 624 c++ ternarysearchtree.exe!std::shared_ptr::reset() line 649 c++ ternarysearchtree.exe!ternarysearchtreenode::~ternarysearchtreenode() line 50 c++

ternarysearchtree.exe!ternarysearchtree::insertword(std::basic_string,std::allocator word) line 105 c++ ternarysearchtree.exe!ternarysearchtree::populatetreefromtextfile(std::basic_string,std::allocator filename) line 182 c++ ternarysearchtree.exe!wmain(int argc, wchar_t * * argv) line 200 c++ ternarysearchtree.exe!__tmaincrtstartup() line 533 c ternarysearchtree.exe!wmaincrtstartup() line 377 c kernel32.dll!7592338a() unknown [frames below may incorrect and/or missing, no symbols loaded kernel32.dll]
ntdll.dll!77599f72() unknown ntdll.dll!77599f45() unknown

thanks can provide! , let me know if there anythign else need me provide (the text file reading in has word cornin it).

your problem you're using java style in c++. unlike in java pointer, in c++ have think difference between values, references, pointers, , object lifetime.

this function bad:

ternarysearchtreenode::ternarysearchtreenode(char character, bool end_of_word,                                              ternarysearchtreenode left_node,                                               ternarysearchtreenode centre_node,                                               ternarysearchtreenode right_node) {    character_ = character;   end_of_word_ = end_of_word;   left_node_.reset(&left_node);   centre_node_.reset(&centre_node);   right_node_.reset(&right_node); } 

you taking ternarysearchtreenode objects value, putting address shared_ptr. point of shared_ptr to take ownership of dynamically allocated object (one created using new) , delete when reference count goes zero. objects above (left_node, etc) stack objects go out of scope @ end of function. when put address shared_ptr, try delete objects later, no longer exist.

as far recommending how fix this, there whole lot going on here assumptions off. instance, can child node have more 1 parent? make sense copy nodes?

i'll assume moment copying nodes makes sense, using shared_ptr reasonable. in case might start here:

ternarysearchtreenode ternarysearchtree::insertnode(std::shared_ptr<ternarysearchtreenode currentnode>,                                                      char character,                                                     nodeposition position,                                                     bool isroot) {    auto newnode = std::make_shared<ternarysearchtreenode>();   newnode->set_character(character);    if (!isroot) {     switch (position) {     case node_pos_left:       currentnode->set_left_node(newnode); 

then of functions set_left_node should take std::shared_ptr<ternarysearchnode> parameters. should not calling reset(), exists allow shared_ptr take ownership (refcount == 1) of free pointer. shared_ptr works incrementing reference count on copy , dereferencing in destructor. when dereference pointer , take address, working around shared_ptr.


Comments

Popular posts from this blog

ruby on rails - RuntimeError: Circular dependency detected while autoloading constant - ActiveAdmin.register Role -

c++ - OpenMP unpredictable overhead -

javascript - Wordpress slider, not displayed 100% width -