gpt4 book ai didi

c++ - GCC 和 MSVC 之间的文件输出不一致

转载 作者:行者123 更新时间:2023-11-28 02:04:56 25 4
gpt4 key购买 nike

考虑下面的类,这是一个简单的文件加载类,用于通过在构造期间将数据加载到内存中来操作小文本文件。

#include <fstream>
#include <ostream>
#include <stdexcept>
#include <string>
#include <vector>

class file_loader {
public:
/**
* \brief Constructs a file_loader instance using a given filename. Caches the file contents
* into the internal cached storage container.
*
* \param _filename Name/directory of file to load.
* \param _max_line_length Optional, approximate maximum length of file lines.
*/
file_loader(const std::string& _filename, std::size_t _max_line_length = static_cast<std::size_t>(256)) : fs(_filename), filename(_filename) {
cache_contents(_max_line_length);
}
/**
* \brief Deleted copy construction, copy constructing is forbidden.
*/
file_loader(const file_loader& _other) = delete;
/**
* \brief Move constructor, moves a given file_loader instance to this leaving the
* parameterised instance in a valid but unspecified state.
*
* \param _other rvalue reference to a file_loader instance to move.
*/
file_loader(file_loader&& _other) : fs(std::move(_other.fs)), filename(std::move(_other.filename)),
cached_contents_vec(std::move(_other.cached_contents_vec)) { }

/**
* \brief Writes all changes made to the internal cached storage to the
* filestream, overwriting the current contents of the file.
*/
void write_changes() {
fs.close();
fs.open(filename);
fs.clear();
write_cache();
}
/**
* \brief Reads a given line of the internal cached storage. This internal
* store is guaranteed to always be up to date, no call to write_changes
* is required to maintain consistency.
*
* \param _n Line number to read.
* \return const reference to std::string instance given by _n'th line.
* \throws Throws std::out_of_range exception if _n exceeds lines in internal cached storage.
*/
const std::string& read_line(std::size_t _n) const {
if (_n >= cached_contents_vec.size())
throw std::out_of_range("File: " + filename + " does not have " + std::to_string(_n) + " lines.");
return cached_contents_vec[_n];
}

/**
* \brief Overwrites a given line of the internal cached storage such that
* the next call to write_changes will update the file contents.
*
* \param _n Line number to overwrite.
* \param _str std::string instance to overwrite current line contents with.
* \throws Throws std::out_of_range exception if _n exceeds lines in internal cached storage.
*/
void overwrite_line(std::size_t _n, const std::string& _str) {
if (_n >= cached_contents_vec.size())
throw std::out_of_range("File: " + filename + " does not have " + std::to_string(_n) + " lines.");
cached_contents_vec[_n] = _str;
}
/**
* \brief Erases a given line of the internal cached storage such that
* the next call to write_changes will update the file contents.
*
* \param _n Line number to erase.
* \return Iterator to next valid position in internal cached storage container.
*/
auto erase_line(std::size_t _n) {
return cached_contents_vec.erase(cached_contents_vec.begin()+_n);
}

/**
* \brief Deleted copy assignment operator, copy assignment is forbidden.
*/
file_loader& operator=(const file_loader& _other) = delete;
/**
* \brief Move assignment operator, uses move-semantics to move the parameterised
* file_loader instance to this. Instance being moved is left in a
* valid but unspecified state.
*
* \param _other rvalue reference to file_loader instance.
*/
file_loader& operator=(file_loader&& _other) {
// check for self-assignment
if (this != &_other) {
fs = std::move(_other.fs);
filename = std::move(_other.filename);
cached_contents_vec = std::move(_other.cached_contents_vec);
}
return *this;
}
private:
std::fstream fs;
std::string filename;
std::vector<std::string> cached_contents_vec; // internal cached storage container

/**
* \brief Caches contents of files into the internal cached storage container.
*
* \param _max_line_length Approximate maximum line length of the file, used for performance improvements.
*/
void cache_contents(std::size_t _max_line_length) {
std::string line_str;
// reserve space for performance
line_str.reserve(_max_line_length);
while (std::getline(fs, line_str)) {
cached_contents_vec.push_back(line_str);
}
}

/**
* \brief Convenience method for writing a std::vector<std::string> to an std::ostream instance.
*
* \param _os Instance of std::ostream.
* \param _vec Instance of std::vector<std::string> to write to _os.
* \return Reference to _os modified with data of _vec.
*/
void write_cache() {
for (const auto& x : cached_contents_vec) {
fs << x << "\n";
}
}

};

通过 GCC (6.1.0)MSVC (2015) 执行时,使用此类似乎会产生不同的结果。假设我有以下文本文件 (test.txt):

cheese
ham
eggs
beef
bacon

和以下主要:

int main(void) {
file_loader fl("test.txt");
fl.overwrite_line(3, "chicken");
fl.write_changes();
}

MSVC 中它产生了我预期的结果:

cheese
ham
eggs
chicken
bacon

但是在 GCC (6.1.0) 中我得到:

cheese
ham
eggs
chickenbacon

换句话说,后者似乎将被覆盖的行和下面的行“连接”到 cached_contents_vec 的单个条目中,而前者将条目分开(因为它们应该尽可能远我知道这种情况)。

知道这里发生了什么吗?我还应该提到,在 file_loader::write_changes() 中,MSVC 不需要此方法中的两个初始行来覆盖以前的文件内容,而 GCC 需要。

最佳答案

正如@IgorTandetnik 评论的那样,这里的问题在于 GCC 生成 Unix 风格的行结束符,而 MSVC 生成基于 Windows 的行结束符。当在简单的文本编辑器(如记事本)中查看输出时,GCC 的 Unix 风格输出不会被视为行尾指示符,而在“更好”的编辑器(例如 Notepad++ )中打开时,它会被正确处理并产生相同的输出两种情况。

关于c++ - GCC 和 MSVC 之间的文件输出不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37902501/

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