我正在尝试实现一个表示文件连接的类,因此它应该是一个不可复制的类。此外,由于创建对象需要文件名,我想删除默认构造函数。
以下是此类的简化定义:
class Elem
{
public:
Elem() = delete;
Elem(string name) : file(new ifstream(name,ios::in)) {}
Elem(const Elem&) = delete;
Elem& operator=(const Elem& o) = delete;
Elem& operator=(Elem && o)
{
swap(o.file,file);
o.file = nullptr;
}
Elem(Elem &&o) : file(nullptr)
{
swap(file,o.file);
}
~Elem()
{
if(file!=nullptr){
file->close();
delete file;
}
}
protected:
ifstream* file;
};
但是,当我尝试将这些对象存储在标准映射中时,代码无法编译:
int main(){
map<string,Elem> m;
m["file1"] = move(Elem("file1"));
cout<<m.size()<<endl;
return 0;
}
我收到以下错误(gcc 4.9.1):
In file included from /usr/include/c++/4.9.1/bits/stl_map.h:63:0,
from /usr/include/c++/4.9.1/map:61,
from test.cpp:1:
/usr/include/c++/4.9.1/tuple: In instantiation of ‘std::pair<_T1, _T2>::pair(std::tuple<_Args1 ...>&, std::tuple<_Args2 ...>&, std::_Index_tuple<_Indexes1 ...>, std::_Index_tuple<_Indexes2 ...>) [with _Args1 = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >&&}; unsigned int ..._Indexes1 = {0u}; _Args2 = {}; unsigned int ..._Indexes2 = {}; _T1 = const std::basic_string<char>; _T2 = Elem]’
/usr/include/c++/4.9.1/tuple:1088:63: required from ‘std::pair<_T1, _T2>::pair(std::piecewise_construct_t, std::tuple<_Args1 ...>, std::tuple<_Args2 ...>) [with _Args1 = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >&&}; _Args2 = {}; _T1 = const std::basic_string<char>; _T2 = Elem]’
/usr/include/c++/4.9.1/ext/new_allocator.h:120:4: required from ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::pair<const std::basic_string<char>, Elem>; _Args = {const std::piecewise_construct_t&, std::tuple<std::basic_string<char, std::char_traits<char>, std::allocator<char> >&&>, std::tuple<>}; _Tp = std::_Rb_tree_node<std::pair<const std::basic_string<char>, Elem> >]’
/usr/include/c++/4.9.1/bits/alloc_traits.h:253:4: required from ‘static std::_Require<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type> std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::pair<const std::basic_string<char>, Elem>; _Args = {const std::piecewise_construct_t&, std::tuple<std::basic_string<char, std::char_traits<char>, std::allocator<char> >&&>, std::tuple<>}; _Alloc = std::allocator<std::_Rb_tree_node<std::pair<const std::basic_string<char>, Elem> > >; std::_Require<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type> = void]’
/usr/include/c++/4.9.1/bits/alloc_traits.h:399:57: required from ‘static decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::pair<const std::basic_string<char>, Elem>; _Args = {const std::piecewise_construct_t&, std::tuple<std::basic_string<char, std::char_traits<char>, std::allocator<char> >&&>, std::tuple<>}; _Alloc = std::allocator<std::_Rb_tree_node<std::pair<const std::basic_string<char>, Elem> > >; decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = <type error>]’
/usr/include/c++/4.9.1/bits/stl_tree.h:423:42: required from ‘std::_Rb_tree_node<_Val>* std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_create_node(_Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<std::basic_string<char, std::char_traits<char>, std::allocator<char> >&&>, std::tuple<>}; _Key = std::basic_string<char>; _Val = std::pair<const std::basic_string<char>, Elem>; _KeyOfValue = std::_Select1st<std::pair<const std::basic_string<char>, Elem> >; _Compare = std::less<std::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::basic_string<char>, Elem> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<std::pair<const std::basic_string<char>, Elem> >*]’
/usr/include/c++/4.9.1/bits/stl_tree.h:1790:64: required from ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_emplace_hint_unique(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator, _Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<std::basic_string<char, std::char_traits<char>, std::allocator<char> >&&>, std::tuple<>}; _Key = std::basic_string<char>; _Val = std::pair<const std::basic_string<char>, Elem>; _KeyOfValue = std::_Select1st<std::pair<const std::basic_string<char>, Elem> >; _Compare = std::less<std::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::basic_string<char>, Elem> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::pair<const std::basic_string<char>, Elem> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator = std::_Rb_tree_const_iterator<std::pair<const std::basic_string<char>, Elem> >]’
/usr/include/c++/4.9.1/bits/stl_map.h:519:8: required from ‘std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](std::map<_Key, _Tp, _Compare, _Alloc>::key_type&&) [with _Key = std::basic_string<char>; _Tp = Elem; _Compare = std::less<std::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::basic_string<char>, Elem> >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = Elem; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = std::basic_string<char>]’
test.cpp:41:14: required from here
/usr/include/c++/4.9.1/tuple:1099:70: erreur: use of deleted function ‘Elem::Elem()’
second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
^
test.cpp:11:5: note: declared here
Elem() = delete;
有关如何实现这一目标的任何线索?他们的结构中存在其他设计缺陷吗?
提前致谢
答案 0 :(得分:3)
您正在做的是:
map<string,Elem> m;
m["file1"] = // this default-constructs an Elem
// and returns a reference to it in the correct spot
move(Elem("file1")); // and THEN move-assigns it
您需要做什么:
map<string, Elem> m;
m.emplace("file1", Elem("file1"));
或
m.insert(std::make_pair("file1", Elem("file1"));
或
m.emplace(std::piecewise_construct,
std::forward_as_tuple("file1"),
std::forward_as_tuple("file1"));
至于您的设计,评论指出了您可能泄漏流的问题。但这实际上是一个非常简单的解决方案。您所表达的是对文件的唯一所有权,其中所有权可以转让。有一种类型:unique_ptr
!
class Elem {
std::unique_ptr<ifstream> file;
public:
Elem() = delete;
Elem(string name) : file(new ifstream(name,ios::in)) {}
Elem(Elem&& ) = default;
Elem& operator=(Elem&& ) = default;
~Elem() = default;
Elem(const Elem&) = delete;
Elem& operator=(const Elem&) = delete;
};
使用unique_ptr
使得default
/ delete
行甚至不需要(默认构造函数除外 - 因为这是您要求执行的要求),这是甚至更好(见零规则)。我只是为了清晰起见而对它们进行了说明。