使用memset为Union分配内存时内存泄漏

时间:2017-09-25 23:49:39

标签: c++ c++11 memory memory-leaks

对于C ++ 11及以上版本:
ad_tree_node是指Union数据结构,旨在保存类型为ad_node的{​​{1}}或vary_node类型的对象。

代码编译但与struct一起使用时会检测到内存泄漏。

以下是代码:

valgrind

使用以下标志编译: struct ad_node { std::string tag_; int count_; std::vector<int> index_; bool leaf_; }; struct vary_node { std::string tag_; int index_; int mcv_; }; union ad_tree_node { ad_node ad; vary_node vy; ad_tree_node () { std::memset(this, 0, sizeof(ad_node)); } ~ad_tree_node() {} }; std::string print_ad_tree_node(const ad_tree_node& nd, bool is_ad_node) { std::string st = ""; if (is_ad_node) { st += "ad_node: " + nd.ad.tag_+ ", " + std::to_string(nd.ad.count_) + ", "; if (nd.ad.leaf_) { st += " leaf, "; } else { st += "non-leaf, "; } st += "index: "; std::cout << nd.ad.index_.size(); for (auto x : nd.ad.index_) { st += std::to_string(x) + ", "; } } else { st += "vy_node: " + nd.vy.tag_ + ", mcv_: " + std::to_string(nd.vy.mcv_) + ", "; st += "index: "; std::cout << nd.vy.index_; } return st; } int main () { ad_node t1; for (int i = 0; i < 10; ++i) t1.index_.push_back(i); t1.tag_ = "A"; t1.leaf_ = true; t1.count_ = 9; ad_tree_node nd; nd.ad.tag_ = t1.tag_; nd.ad.leaf_ = t1.leaf_; nd.ad.count_ = t1.count_; nd.ad.index_ = std::move(t1.index_); std::cout << print_ad_tree_node(nd, true) << std::endl; return 0; }
g++ -std=c++11 -g3 code.cpp

valgrind --leak-check=full ./a.out报告的泄漏

valgrind:

1 个答案:

答案 0 :(得分:4)

ad_tree_node的析构函数只是{}。与普通类类型不同,其析构函数将自动为每个基类和每个成员对象调用析构函数,对于联合,您必须自己完成所有操作。在这种情况下,~ad_tree_node()不会调用~ad_node(),因此std::stringstd::vector成员分配的所有内存都会泄露。这正是valgrind所抱怨的。

您还遇到memset的问题 - 这与非标准布局类型无法很好地协作。 memset - stringvector是UB。

真正想要的是一个变体:

using ad_tree_node = variant<ad_node, vary_node>;

用C ++的说法,variant就像union - 除了它知道它包含哪种类型,按照C ++对象语义正确管理其存储,并自行清理。对于C ++ 11,一个很好的实现是Boost.Variant。