[英]Do I need to set my destructor methods when I am using shared pointers?
我試圖找到一個答案,但沒有找到針對我特定問題的答案。 我正在為三元搜索樹使用共享指針(用於預測文本算法),並且使用共享指針遇到了一些問題。
我離開C ++已經5年了,讓我告訴你,Java不能幫助您學習指針。 在過去的幾天里,我不得不重新學習了5-6年前在學校學習的指針材料,並且成功地破壞了我的代碼。
這是我擁有的大多數代碼:
// 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 a copy of the node then swap the new one with it
//do this first to 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 from string to 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 a node
TernarySearchTreeNode TernarySearchTree::InsertNode(TernarySearchTreeNode ¤tNode,
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 a 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 to a node while traversing
//Base case where there is no root node
if (!root_node_) {
for(std::vector<char>::iterator it = characters.begin(); it != characters.end(); ++it) {
if (*it != '\0') {
//if it is the first character
//root_node_ is equal to the 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, then we need to compare each character
} else {
currentNode = root_node_;
for(std::vector<char>::iterator it = characters.begin(); it != characters.end(); ++it) {
if (*it != '\0') {
currentNode.reset(&SetNextNode(*currentNode, *it, *std::next(it, 1)));
} else {
currentNode->set_end_of_word(true);
}
}
}
}
//Recursive function for obtaining/adding the next node when inserting a word
TernarySearchTreeNode TernarySearchTree::SetNextNode(TernarySearchTreeNode ¤tNode, 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 a new node and recall method on that node
} else {
//If not the end of the word, make a new node with the next letter
if (nextChar != '\0') {
return InsertNode(currentNode, nextChar, NODE_POS_CENTRE, false);
} else {
return currentNode;
}
}
//If it is less, follow node on the 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 a new node and recall method on that node
} else {
return SetNextNode(InsertNode(currentNode, currentChar, NODE_POS_LEFT, false), currentChar, nextChar);
}
//Otherwise it is bigger, so 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 a new node and recall method on that node
} else {
return SetNextNode(InsertNode(currentNode, currentChar, NODE_POS_RIGHT, false), currentChar, nextChar);
}
}
}
//Populate the TST from a 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 one 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 at root and follow some paths
std::cout << tst.get_root_node();
/**std::vector<char> vec;
vec.push_back('a');
vec.push_back('c');
std::vector<char>::iterator it = 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;
}
對於節點:
/*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(¢reNode);
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(¢re_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(¢reNode);
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 to stream
char c = obj.get_character();
bool b = obj.is_end_of_word();
os << c << "\t is end of word: " << b;
return os;
}
當我在調試模式(Visual Studios)中運行時,它能夠設置根節點,但是當它輸入第二個節點時,當currentNode在else語句中調用.reset(&node)時,嘗試刪除“東西”會崩潰。函數InsertWord 。 我在復制構造函數或operator =方法或析構函數中做錯什么了嗎? 它上方的cout行確實會打印正確的字母,因此看起來該節點已正確創建。
調試調用堆棧顯示:
TernarySearchTree.exe!std :: _ Ref_count_base :: _ Decref()第118行C ++ TernarySearchTree.exe!std :: _ Ptr_base :: _ Decref()第347 C ++ TernarySearchTree.exe!std :: shared_ptr ::〜shared_ptr()第624行C ++ TernarySearchTree .exe!std :: shared_ptr :: reset()第649行C ++ TernarySearchTree.exe!TernarySearchTreeNode ::〜TernarySearchTreeNode()第50行C ++ TernarySearchTree.exe!TernarySearchTreeNode:`標量刪除析構函數(unsigned int)C ++ TernarySearchTree.exe! std :: _ Ref_count :: _ Destroy()第161行C ++ TernarySearchTree.exe!std :: _ Ref_count_base :: _ Decref()第120行C ++ TernarySearchTree.exe!std :: _ Ptr_base :: _ Decref()第347行C ++ TernarySearchTree.exe!std: :shared_ptr :: ~~ shared_ptr()第624行C ++ TernarySearchTree.exe!std :: shared_ptr :: reset()第649行C ++ TernarySearchTree.exe!TernarySearchTreeNode ::〜TernarySearchTreeNode()第50行C ++
TernarySearchTree.exe!TernarySearchTree :: InsertWord(std :: basic_string,std :: allocator word)第105行C ++ TernarySearchTree.exe!TernarySearchTree :: PopulateTreeFromTextFile(std :: basic_string,std :: allocator fileName)第182行C ++ TernarySearchTree.exe! wmain(int argc,wchar_t * * argv)第200行C ++ TernarySearchTree.exe!__ tmainCRTStartup()第533行C TernarySearchTree.exe!wmainCRTStartup()第377 C C kernel32.dll!7592338a()未知[下面的幀可能不正確和/或丟失,沒有為kernel32.dll加載任何符號]
ntdll.dll!77599f72()未知ntdll.dll!77599f45()未知
感謝您的任何幫助,您可以提供! 並且讓我知道您是否還有其他需要我提供的內容(我正在閱讀的文本文件中包含corn
這個詞)。
您的問題是您在C ++中使用Java樣式。 與Java中的一切本質上都是指針不同,在Java中,您必須考慮值,引用,指針和對象生存期之間的差異。
此功能不好:
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(¢re_node);
right_node_.reset(&right_node);
}
您TernarySearchTreeNode
值獲取TernarySearchTreeNode
對象,然后將其地址放入shared_ptr
。 shared_ptr
獲取動態分配的對象(使用new
創建的對象)的所有權並在引用計數為零時將其刪除的點。 上面的對象(left_node等)是堆棧對象,將在函數末尾超出范圍。 當將它們的地址放入shared_ptr
,它將稍后嘗試刪除那些對象,但它們不再存在。
至於如何解決此問題的建議,這里有很多假設尚在進行中。 例如,一個子節點可以有多個父節點嗎? 復制節點實際上有意義嗎?
我現在假設復制節點是有意義的,因此使用shared_ptr
是合理的。 在這種情況下,我們可以從這里開始:
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);
然后,所有函數(例如set_left_node
也應將std::shared_ptr<TernarySearchNode>
作為參數。 您不應該調用reset()
,它存在是為了允許shared_ptr
獲取自由指針的所有權(refcount == 1)。 shared_ptr
通過增加副本上的引用計數並在析構函數中取消引用來工作。 當取消引用指針然后獲取地址時,您正在使用shared_ptr。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.