提升::变体; std::unique_ptr 和复制
Posted
技术标签:
【中文标题】提升::变体; std::unique_ptr 和复制【英文标题】:boost::variant; std::unique_ptr and copy 【发布时间】:2013-03-28 18:43:42 【问题描述】:此问题确定不可复制类型不能与 Boost Variant 一起使用
Tree
类
template <class T = int>
class Tree
private:
class TreeNode
public:
std::unique_ptr Nodes
Move constructors and move assignment + other public members
private:
TreeNode(const TreeNode &other); (= delete not supported on compiler)
TreeNode& operator=(const TreeNode &rhs); (= delete not supported on compiler)
; // End Tree Node Class Definition
Tree(const Tree &other); (= delete not supported on compiler)
Tree& operator=(const Tree &rhs); (= delete not supported on compiler)
public:
Move constructors and move assignment + other public members
;
TreeVisitor
类
class TreeVisitor : public boost::static_visitor<bool>
public:
TreeVisitor()
bool operator() (BinarySearchTree<std::string>& tree) const
return searchTree.load(tree);
private:
;
TreeVariant
typedef boost::variant<Tree<std::string>, Tree<int>> TreeVariant;
TreeVariant tree;
Tree<std::string> stringTree;
Tree<int> intTree;
申请Visitors
如下
tree = intSearchTree;
boost::apply_visitor(TreeVisitor(), tree)
还使用 boost::bind 来获取所需的参数
boost::bind(TreeVisitor(), tree, val, keyIndex);
类型的编译器错误
error C2248: 'Tree<T>::Tree' : cannot access private member declared in class 'Tree<T>' <----- related to private copy constructor in Tree (not TreeNode)
tree = stringTree; <------- error related to assignment
Tree
编译正确并经过测试。如何解决这些编译错误,这些错误似乎与尝试获取 Tree
类的副本有关,而由于 std::unique_ptr
,这是不可能的?
SSCCE
<class T = int>
class Tree
private:
class TreeNode
public:
TreeNode()
~TreeNode()
TreeNode(TreeNode &&other) :
key(other.key), index(other.index), left(std::move(other.left)), right(std::move(other.right))
key = index = left = right = nullptr;
TreeNode &operator=(BTreeNode &&rhs)
if(this != &rhs)
key = rhs.key; index = rhs.index;
left = std::move(rhs.left); right = std::move(rhs.right);
rhs.key = rhs.index = rhs.left = rhs.right = nullptr;
return *this;
TreeNode(const T &new_key, const T &new_index) :
key(new_key), index(new_index), left(nullptr), right(nullptr)
friend class Tree;
private:
TreeNode(const BinarySearchTreeNode &other);
TreeNode& operator=(const BinarySearchTreeNode &rhs);
std::unique_ptr<TreeNode> left;
std::unique_ptr<TreeNode> right;
; // End Tree Node Class Definition
std::unique_ptr<TreeNode> root;
BinarySearchTree(const BinarySearchTree &other);
BinarySearchTree& operator=(const BinarySearchTree &rhs);
public:
Tree() : root(nullptr), flag(false), run(true), leftCount(0), rightCount(0)
~Tree()
Tree(BinarySearchTree &&other) : root(std::move(other.root)) other.root = nullptr;
Tree &operator=(BinarySearchTree &&rhs)
if(this != &rhs)
root = std::move(rhs.root);
rhs.root = nullptr;
return *this;
;
使用示例:
bool delete_()
while(!instances.empty())
// grab first instance
keyIndex = instances.at(0);
// compute end of the tuple to delete
endIndex = keyIndex + sizeToDelete;
// read the first attribute
try
temp = boost::trim_copy(dataFile->readData(keyIndex, domainSize));
catch (std::exception &e)
printw("Error reading from the data file");
// delete tuple from data file
if(!dataFile->deleteTuple(keyIndex, endIndex))
printw("Error attempting to remove tuple");
if (writer_ != nullptr)
writer_ << "Error attempting to remove tuple";
try
printw("%s");
// close catalog and search file
catch (std::exception &e)
e.what();
// close data file
dataFile->closeFile();
return false;
try
int val = boost::lexical_cast<int>(temp);
searchTree = intSearchTree;
boost::bind(BinarySearchTreeVisitor(), searchTree, val, keyIndex);
// delete key index from the index file
if (!boost::apply_visitor(BinarySearchTreeVisitor(), searchTree))
printw("No index present in index file");
try
printw(" ");
catch (std::exception &e)
// close data file
dataFile->closeFile();
return false;
catch(boost::bad_lexical_cast &e)
/*
* Must be a std::string --- wow who knew
*/
searchTree = stringSearchTree;
boost::bind(BinarySearchTreeVisitor(), searchTree, temp, keyIndex);
// delete key index from the index file
if (!boost::apply_visitor(BinarySearchTreeVisitor(), searchTree))
printw("No index present in index file");
try
printw(" ");
// close catalog and search file
catch (std::exception &e)
e.what();
// close data file
dataFile->closeFile();
return false;
// clean up the index file
boost::bind(BinarySearchTreeVisitor(), searchTree, keyIndex, sizeToDelete);
boost::apply_visitor(BinarySearchTreeVisitor(), searchTree);
instances.erase(instances.begin());
for(int i= 0; i < instances.size(); i++)
instances.assign(i, instances.at(i) -
sizeToDelete);
【问题讨论】:
请发布可编译的代码。 (并且仍然演示问题)删除不重要但仍然演示问题的内容。看这里:sscce.org 了解如何让您的问题更容易回答。 @Yakk 我的原始帖子尽可能清楚地说明了一个包含十个类和数千行代码的程序的问题。无需您无限滚动,它就可以做到最好。 不,不是。您的TreeVisitor
正在谈论BinarySearchTree
,这是一种不知从何而来的类型。 Tree
应该是 BinarySearchTree
吗?几乎你所有的delete_
函数都与问题无关,你怎么能得到它? TreeNode
的成员是否与问题有关?我对此表示怀疑。一个简短的、自包含的编译示例的全部意义在于,您实际上编写了编译并演示问题的代码,并且在仍然演示问题的同时,您可以从中删除所有可以消除的内容。你可以做得更好。
并且说“将构造函数移到这里”是没有帮助的。如果它们不重要,请忽略它们。如果它们很重要,请包括它们,并尽可能多地从它们中删除,直到它们只包含重要的部分。然后重复。
@Yakk 将 BinarySearchTree
更正为 Tree
并发布了 SSCCE。我试图提供的不是 SSCCE,而是我正在编写的一个非常大的程序的可理解的细分。很抱歉你的例外,并真诚地向你道歉!
【参考方案1】:
关于对boost::bind()
的调用,您应该在通过引用将对象传递给按值接受相应参数的函数模板时使用boost::ref()
,否则将尝试复制(这在这种情况下会导致编译器错误,因为无法访问复制构造函数):
boost::bind(TreeVisitor(), boost::ref(tree), val, keyIndex);
// ^^^^^^^^^^^^^^^^
但是,这里有一个更大的问题:boost::variant
只能保存可复制构造的类型。来自Boost.Variant online documentation:
对有界类型的要求如下:
CopyConstructible
[20.1.3]。析构函数支持不抛出异常的安全保证。
在变体模板实例化点完成。 (有关接受不完整类型以启用递归变体类型的类型包装器,请参阅
boost::recursive_wrapper<T>
。)指定为
variant
的模板参数的每种类型都必须至少满足上述要求。 [...]
【讨论】:
我使用std::ref
包裹tree
,编译器发出error C2558: class 'boost::_bi::list3<A1,A2,A3>' : no copy constructor available or copy constructor is declared 'explicit'
`with A1=boost::_bi::value<:reference_wrapper> A2=boost:: _bi::valueboost::ref
怎么样?如果这不起作用,我将删除此答案
似乎工作;编译器声明 error C2248: 'Tree<T>::Tree' : cannot access private member declared in class 'Tree<T>'
并且 tree = stringTree
存在问题,我认为这可能需要 std::move
。
@Mushy:是的,确实如此。 tree = stringTree
将尝试复制构造
我认为CopyConstructible
的要求是一个文档错误——来自Boost 1.53.0 change notes:“变体:添加了右值构造函数和右值赋值运算符(仅适用于与 C++11 兼容的编译器)。库现在可以与仅移动类型一起使用。"【参考方案2】:
using Mixed = boost::variant<
std::unique_ptr<char>,
std::unique_ptr<short>,
std::unique_ptr<int>,
std::unique_ptr<unsigned long>
>;
int main()
auto md = std::unique_ptr<int>(new int(123));
Mixed mixed = std::move(md);
std::cout << *boost::get< std::unique_ptr<int> >(mixed) << std::endl;
return 0;
unique_ptr 是只能移动的,可以在变体中使用。上面的例子可以编译和工作(C++11)。
【讨论】:
以上是关于提升::变体; std::unique_ptr 和复制的主要内容,如果未能解决你的问题,请参考以下文章
`std::optional` 比 `std::shared_ptr` 和 `std::unique_ptr` 有啥优势?
std :: list可以包含不同的std :: unique_ptr ?