gpt4 book ai didi

c++ - 使用共享指针时是否需要设置析构函数方法?

转载 作者:行者123 更新时间:2023-11-30 01:16:07 31 4
gpt4 key购买 nike

我尝试寻找答案,但没有找到适合我的特定问题的答案。我正在为三元搜索树(用于预测文本算法)使用共享指针,但在使用共享指针时遇到了一些问题。

我已经离开C++ 5年了,我告诉你,Java不帮你学指针。在过去的几天里,我不得不重新学习 5-6 年前在学校学到的指针 Material ,并成功地破坏了我的代码。

这是我拥有的大部分代码:

// 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 &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 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 &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 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(&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 to stream
char c = obj.get_character();
bool b = obj.is_end_of_word();

os << c << "\t is end of word: " << b;
return os;
}

当我在 Debug模式 (Visual Studios) 中运行时,它能够设置根节点,但是当它输入第二个节点时,当 currentNode 在内部调用 .reset(&node) 时,它试图删除“stuff”时崩溃函数 InsertWord 的 else 语句。我在复制构造函数或 operator= 方法或析构函数中做错了什么吗?它上面的 cout 行确实打印了正确的字母,因此看起来节点已正确创建。

调试调用堆栈显示:

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 be incorrect and/or missing, no symbols loaded for kernel32.dll]
ntdll.dll!77599f72() Unknown ntdll.dll!77599f45() Unknown

感谢您提供的任何帮助!如果您还需要我提供任何其他信息,请告诉我(我正在阅读的文本文件中只有 corn 一词)。

最佳答案

您的问题是您在 C++ 中使用 Java 样式。在 Java 中,一切本质上都是指针,而在 C++ 中,您必须考虑值、引用、指针和对象生命周期之间的区别。

这个函数不好:

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

您正在服用 TernarySearchTreeNode value 对象,然后将它们的地址放入 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。

关于c++ - 使用共享指针时是否需要设置析构函数方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27240038/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com