std::vector<std::ofstream>::erase出现编译错误

3

你好,我正在尝试进行一些文件操作,如果需要,用户可以打开多个文件。我创建了一个派生自ofstream的向量,但是当我想要使用std::vector<Type>::erase(std::vector<Type>::iterator)删除已关闭的文件时,编译器会报错,但我有另一个派生自std::string的向量,并且我以相同的方式删除它,它没有出现错误。我的代码如下:

#include <iostream>
#include <fstream>
#include <vector>

std::vector<std::ofstream> of;
std::vector<std::string> sv;

int CloseFile(int id, file_t ft) {
    std::vector<std::ofstream>::iterator i;
    std::vector<std::string>::iterator j;
    if (of[id].is_open() == true) {
        of[id].close();
        i = of.begin() + id;
        j = sv.begin() + id;
        of.erase(i); // showing error for this line
        sv.erase(j);
    }
}

我正在使用Ubuntu 12.04上的Nsight Eclipse Edition 6.0,我需要打开文件或文件夹,但是来自Eclipse输出的问题部分的错误如下:
  1. 需要从'_OI std :: __ copy_move_a(_II,_II,_OI)[with bool _IsMove = false; _II = std :: basic_ofstream ; _OI = std :: basic_ofstream ]'
  2. 需要从'_OI std :: __ copy_move_a2(_II,_II,_OI)[with bool _IsMove = false; _II = __gnu_cxx :: __ normal_iterator *,std :: vector > > ;; _OI = __gnu_cxx :: __ normal_iterator *,std :: vector > >]'
  3. 需要从'_OI std :: copy(_II,_II,_OI)[with _II = __gnu_cxx :: __ normal_iterator *,std :: vector > > ;; _OI = __gnu_cxx :: __ normal_iterator *,std :: vector > >]'
  4. 需要从'_OI std :: copy(_II,_II,_OI)[with _II = __gnu_cxx :: __ normal_iterator *,std :: vector > > ;; _OI = __gnu_cxx :: __ normal_iterator *,std :: vector > >]'
  5. std :: basic_streambuf<_CharT,_Traits>& std :: basic_streambuf<_CharT,_Traits> :: operator =(const std :: basic_streambuf<_CharT,_Traits>&)[with _CharT = char; _Traits = std :: char_traits]
  6. std :: ios_base& std :: ios_base :: operator =(const std :: ios_base&)
  7. make:*** [dosya / dosya.o]错误1
  8. 在此内容中
  9. 在此内容中
  10. 需要从这里
最后一个指示代码行的错误 编译器输出: (一些单词是土耳其语,dosya =文件,GeriDonus_t = Return_t,DosyaKapat = FileClose)
16:06:56 **** Incremental Build of configuration Debug for project deneme ****`
make all`
Building file: ../dosya/dosya.cpp`
Invoking: NVCC Compiler`
/usr/local/cuda-6.0/bin/nvcc -I"/usr/local/cuda-6.0/samples/3_Imaging" -I"/usr/local    /cuda-6.0/samples/common/inc" -I"/opt/Calismalar/Cuda/cuda-workspace/deneme" -I/usr/local/opencv/include -I/usr/local/opencv/include/opencv -I/opt/Calismalar/Cuda/cuda-workspace/deneme/ -G -g -O0 -gencode arch=compute_30,code=sm_30 -gencode arch=compute_32,code=sm_32  -odir "dosya" -M -o "dosya/dosya.d" "../dosya/dosya.cpp"`
nvcc warning : The 'compute_10' and 'sm_10' architectures are deprecated, and may be removed in a future release.`
/usr/local/cuda-6.0/bin/nvcc -I"/usr/local/cuda-6.0/samples/3_Imaging" -I"/usr/local/cuda-6.0/samples/common/inc" -I"/opt/Calismalar/Cuda/cuda-workspace/deneme" -I/usr/local/opencv/include -I/usr/local/opencv/include/opencv -I/opt/Calismalar/Cuda/cuda-workspace/deneme/ -G -g -O0 --compile  -x c++ -o  "dosya/dosya.o" "../dosya/dosya.cpp"
In file included from /usr/include/c++/4.8/ios:42:0,
                 from /usr/include/c++/4.8/ostream:38,
                 from /usr/include/c++/4.8/iostream:39,
                 from ../dosya/dosya.h:13,
                 from ../dosya/dosya.cpp:9:
/usr/include/c++/4.8/bits/basic_ios.h: In instantiation of ‘static _OI std::__copy_move<false, false, std::random_access_iterator_tag>::__copy_m(_II, _II, _OI) [with _II = std::basic_ofstream<char>*; _OI = std::basic_ofstream<char>*]’:
/usr/include/c++/4.8/bits/stl_algobase.h:390:70:   required from ‘_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false; _II = std::basic_ofstream<char>*; _OI = std::basic_ofstream<char>*]’
/usr/include/c++/4.8/bits/stl_algobase.h:428:38:   required from ‘_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false; _II = __gnu_cxx::__normal_iterator<std::basic_ofstream<char>*, std::vector<std::basic_ofstream<char> > >; _OI = __gnu_cxx::__normal_iterator<std::basic_ofstream<char>*, std::vector<std::basic_ofstream<char> > >]’
/usr/include/c++/4.8/bits/stl_algobase.h:460:17:   required from ‘_OI std::copy(_II, _II, _OI) [with _II = __gnu_cxx::__normal_iterator<std::basic_ofstream<char>*, std::vector<std::basic_ofstream<char> > >; _OI = __gnu_cxx::__normal_iterator<std::basic_ofstream<char>*, std::vector<std::basic_ofstream<char> > >]’
/usr/include/c++/4.8/bits/vector.tcc:138:2:   required from ‘std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::erase(std::vector<_Tp, _Alloc>::iterator) [with _Tp = std::basic_ofstream<char>; _Alloc = std::allocator<std::basic_ofstream<char> >; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<std::basic_ofstream<char>*, std::vector<std::basic_ofstream<char> > >; typename std::_Vector_base<_Tp, _Alloc>::pointer = std::basic_ofstream<char>*]’
../dosya/dosya.cpp:152:27:   required from here
/usr/include/c++/4.8/bits/ios_base.h:789:5: error: ‘std::ios_base& std::ios_base::operator=(const std::ios_base&)’ is private
     operator=(const ios_base&);
     ^
In file included from /usr/include/c++/4.8/ios:44:0,
                 from /usr/include/c++/4.8/ostream:38,
                 from /usr/include/c++/4.8/iostream:39,
                 from ../dosya/dosya.h:13,
                 from ../dosya/dosya.cpp:9:
/usr/include/c++/4.8/bits/basic_ios.h:66:11: error: within this context
     class basic_ios : public ios_base
           ^
In file included from /usr/include/c++/4.8/iostream:39:0,
                 from ../dosya/dosya.h:13,
                 from ../dosya/dosya.cpp:9:
/usr/include/c++/4.8/ostream:58:11: note: synthesized method ‘std::basic_ios<char>& std::basic_ios<char>::operator=(const std::basic_ios<char>&)’ first required here 
     class basic_ostream : virtual public basic_ios<_CharT, _Traits>
           ^
In file included from ../dosya/dosya.h:14:0,
                 from ../dosya/dosya.cpp:9:
/usr/include/c++/4.8/fstream:599:11: note: synthesized method ‘std::basic_ostream<char>& std::basic_ostream<char>::operator=(const std::basic_ostream<char>&)’ first required here 
     class basic_ofstream : public basic_ostream<_CharT,_Traits>
           ^
In file included from /usr/include/c++/4.8/ios:43:0,
                 from /usr/include/c++/4.8/ostream:38,
                 from /usr/include/c++/4.8/iostream:39,
                 from ../dosya/dosya.h:13,
                 from ../dosya/dosya.cpp:9:
/usr/include/c++/4.8/streambuf:810:7: error: ‘std::basic_streambuf<_CharT, _Traits>& std::basic_streambuf<_CharT, _Traits>::operator=(const std::basic_streambuf<_CharT, _Traits>&) [with _CharT = char; _Traits = std::char_traits<char>]’ is private
       operator=(const basic_streambuf&) { return *this; };
       ^
In file included from ../dosya/dosya.h:14:0,
                 from ../dosya/dosya.cpp:9:
/usr/include/c++/4.8/fstream:72:11: error: within this context
     class basic_filebuf : public basic_streambuf<_CharT, _Traits>
           ^
/usr/include/c++/4.8/fstream:599:11: note: synthesized method ‘std::basic_filebuf<char>& >std::basic_filebuf<char>::operator=(const std::basic_filebuf<char>&)’ first required here 
     class basic_ofstream : public basic_ostream<_CharT,_Traits>
           ^
In file included from /usr/include/c++/4.8/bits/char_traits.h:39:0,
                 from /usr/include/c++/4.8/ios:40,
                 from /usr/include/c++/4.8/ostream:38,
                 from /usr/include/c++/4.8/iostream:39,
                 from ../dosya/dosya.h:13,
                 from ../dosya/dosya.cpp:9:
/usr/include/c++/4.8/bits/stl_algobase.h:335:18: note: synthesized method ‘std::basic_ofstream<char>& std::basic_ofstream<char>::operator=(const std::basic_ofstream<char>&)’ first required here 
        *__result = *__first;
                  ^
make: *** [dosya/dosya.o] Error 1

16:06:57 Build Finished (took 456ms)`

我对此一无所知。我也查看了这个这个这个这个(关于eclipse的bug),FAQ - q7.1,这个(关于List但是错误相同,并且说其实并不是错误,而且我没有改变编译器(nvcc))。感谢大家。


1
std::ofstream 无法被复制。你需要使用指针。 - molbdnilo
@molbdnilo 谢谢您。 - Orkun Kasapoglu
为什么std::vector使用operator=来添加或删除元素?难道不能使用指针队列或栈,并在删除元素后使用free(void*)吗?这与C++11标准定义有关吗? - Orkun Kasapoglu
我已将向量定义更改为std::vector<std::ofstream*> of;,现在没有错误了,但我还没有尝试过。再次感谢大家。 - Orkun Kasapoglu
建议使用 vector<unique_ptr<ostream>> - Neil Kirk
3个回答

2

Gcc-4.8不支持移动流。就这方面而言,您的代码符合C++11标准,只是实现有问题。


是的,我知道它无法编译或运行。我正在使用土耳其语作为变量名称,并希望代码更易读。我正在进行编辑,抱歉。 - Orkun Kasapoglu
你知道nvcc是基于gcc 4.8还是其他的吗?因为如果代码符合C++11标准,那么基于Gcc 4.8或Nsight Eclipse Edition的nvcc就不兼容C++11,我说的对吗? - Orkun Kasapoglu

1
一个std::vector在连续的内存块中保存它的元素,没有间隙。擦除一个元素会导致所有后面的元素被移动或复制到新的位置。在这种情况下,std::ofstream不能被移动,因此它会产生编译错误。
不要直接在std::vector中使用std::ofstream。它可以与引用、指针或者我更喜欢的std::unique_ptr一起工作。
它也可以使用std::list代替vector。std::list有另一种保存其元素的方式,它不会移动它们。但我不确定这是否比在std:vector中使用引用/指针/std_unique_ptr更好。

3
这个答案在C++98/03标准下是正确的,但在C++11/14标准下是错误的。 - Howard Hinnant
正如我所回答的,在这种情况下它不起作用。在 C++ 11/14 中可能会有所帮助,但如果你从前面开始删除每个元素,最坏情况下会导致大量移动(~n*(n-1)/2)。为了获得高效的代码,即使它能正常工作,也不要这样做。 - Tunichtgut
2
@Tunichtgut: 对于小型集合来说,向量通常是最有效的选择,尽管它的渐近复杂度可能看起来很糟糕。通常只有当“n”变得相当大时,它才会比(理论上)更有效的替代方法不那么高效。 - Mike Seymour
没错,但尝试使用ofstream。一个std:vector、std:deque和std:list,每个容器有10个元素,但没有打开文件。只需创建并停止时间以清除容器('x.erase(x.begin())'适用于所有三个容器)。在10000次运行中累计,我得到了0.021秒的列表,0.017秒的双端队列和0.034秒的向量来删除元素。将元素更改为100个时,列表的时间为0.249秒,双端队列的时间为0.166秒,向量的时间为2.811秒。在10个元素时,向量是稍微不那么有效的容器。在100个元素时,向量完全被淘汰。(VC2013,发布) - Tunichtgut

-2

我已经修改了代码,现在没有错误了。感谢大家。

现在它是这样的:

#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>

std::vector<std::ofstream*> of;
std::vector<std::string> sv;

int CloseFile(int id, file_t ft) {
    std::vector<std::ofstream*>::iterator i;
    std::vector<std::string>::iterator j;
    if (of[id]->is_open() == true) {
        of[id]->close();
        i = of.begin() + id;
        j = sv.begin() + id;
        free(of[id]);
        of.erase(i);
        sv.erase(j);
    }
}

但我还没有尝试过。现在只是没有编译器错误。


-1 这似乎是一个内存泄漏... 其他答案的建议是避免使用 vector::erase() - Walter
@Walter 谢谢,但为什么会出现内存泄漏?如果文件没有被打开,意味着内存尚未分配。 - Orkun Kasapoglu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接