首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

STL中getline的设计大旨

2013-07-04 
STL中getline的设计疏忽方法getline,顾名思义,是获取流中的一行出来,在STL中全局方法getline的定义是:getl

STL中getline的设计疏忽
方法getline,顾名思义,是获取流中的一行出来,在STL中全局方法getline的定义是:


getline(basic_istream<,>& _Istr, basic_stream<,>& _Str);

在basic_istream中的定义是:

getline(_Elem* _Str, streamsize _Count);

既然是获去流中的一行出来,为什么basic_istream中的getline还得加个_Count限制,如果仅是考虑到内存空间的限制,那这种接口的设置不够合理,不知道大家怎么看? STL getline 疏忽
[解决办法]
如果我输入一个1TB字节的a,帖主怎么看?
[解决办法]
istream的成员函数getline的第一个参数是char数组,不管是静态还是动态肯定是有限的,不能自动增长,因此getline时就不能超过这个数组的长度,必须加count限定
全局getline的第二个参数数string,可以自动增长,因此不需要限制长度
[解决办法]
全局的 getline 是定义在 string 头文件里面的.

basic_istream 类是不依赖于 std::string 的, 它都不知道有 std::string 可用, 就只能按传统的字符串方式了.
[解决办法]
同样的还有 fstream 的构造函数和 open 函数, 都是用 char* 做参数的, 而不是用 std::string, 因为不想引入过多的依赖性.
[解决办法]
不只是不想引入依赖性, 由于 std::string 重载了从 istream, ostream 输入输出的, 是 std::string 已经依赖于流了, 如果流在去依赖 std::string 就造成循环依赖了.
看来不是不想, 是不能.
[解决办法]
引用:
不只是不想引入依赖性, 由于 std::string 重载了从 istream, ostream 输入输出的, 是 std::string 已经依赖于流了, 如果流在去依赖 std::string 就造成循环依赖了.
看来不是不想, 是不能.
这说法不对的
流输入输出的重载是在string类外部的,没有对string有依赖
实际上c++11中fstream的open已经支持string作为参数了
[解决办法]
引用:
Quote: 引用:

不只是不想引入依赖性, 由于 std::string 重载了从 istream, ostream 输入输出的, 是 std::string 已经依赖于流了, 如果流在去依赖 std::string 就造成循环依赖了.
看来不是不想, 是不能.

std::string 重载了从 istream, ostream 输入输出?在哪个地方?能否贴出来看一下
在string头文件里啊
cout<<str;这种不是很常用的么
[解决办法]
引用:
Quote: 引用:

不只是不想引入依赖性, 由于 std::string 重载了从 istream, ostream 输入输出的, 是 std::string 已经依赖于流了, 如果流在去依赖 std::string 就造成循环依赖了.
看来不是不想, 是不能.
这说法不对的
流输入输出的重载是在string类外部的,没有对string有依赖
实际上c++11中fstream的open已经支持string作为参数了


虽然是在类外部, 但是标准库只有头文件, 没有 cpp, 还是会在头文件之间引入循环包含的.

fstream 可以使用 std::string 了, 那可能是因为 std::string 依赖的是 istream, 而不是 ifstream 所以依赖关系成了:  istream <-- string <-- ifstream 还是能保持单向. 但是要在 istream 的 getline 函数里引入 string 就恼火了, 会造成循环依赖的.


[解决办法]
循环依赖是允许的?

你能把这样的东西编译过吗


class A
{
public:
B b;
};

class B
{
public:
A a;
};

[解决办法]
派生的类当然可以, string 又没有依赖你的派生类.
[解决办法]
string的实现本身并不需要依赖istream,两者是相互独立的
实际的实现中,string头文件里只是一些string类的外部运算符重载和getline等公用函数,具体的string类通常在内部头文件里定义,istream可以去包含那个
不想增加依赖性这点我是赞同的,但只是不想而已,硬要做到还是可以的
[解决办法]
引用:
string的实现本身并不需要依赖istream,两者是相互独立的
实际的实现中,string头文件里只是一些string类的外部运算符重载和getline等公用函数,具体的string类通常在内部头文件里定义,istream可以去包含那个
不想增加依赖性这点我是赞同的,但只是不想而已,硬要做到还是可以的


要在接口里面使用内部类, 还是不太好吧.
确实是可以把 string 中依赖 istream 的提出去, 多分几个头文件来实现.
[解决办法]
瀑布汗!
因为流是在string类出现之前就先出现的,必须支持char*。
[解决办法]
引用:
Quote: 引用:

istream的成员函数getline的第一个参数是char数组,不管是静态还是动态肯定是有限的,不能自动增长,因此getline时就不能超过这个数组的长度,必须加count限定
全局getline的第二个参数数string,可以自动增长,因此不需要限制长度

这也就是我比较困惑的地方,为什么STL的设计开发人员没想到将_Elem换成string呢?这样不就可以自增长了吗


iostream出现在c++中的时候,stl还不存在,也没有string类。虽然现在已经发展到了basic_istream模板,但还是要考虑对老代码的兼容,这个getline就是那时候的遗留产物。
[解决办法]
引用:
瀑布汗!
因为流是在string类出现之前就先出现的,必须支持char*。


引用:
Quote: 引用:

Quote: 引用:

istream的成员函数getline的第一个参数是char数组,不管是静态还是动态肯定是有限的,不能自动增长,因此getline时就不能超过这个数组的长度,必须加count限定
全局getline的第二个参数数string,可以自动增长,因此不需要限制长度

这也就是我比较困惑的地方,为什么STL的设计开发人员没想到将_Elem换成string呢?这样不就可以自增长了吗


iostream出现在c++中的时候,stl还不存在,也没有string类。虽然现在已经发展到了basic_istream模板,但还是要考虑对老代码的兼容,这个getline就是那时候的遗留产物。


这种说法解释不了为什么 c++11 没有选择增加 istream::getline 重载接受 std::string&,因为这么做并不破坏现有的代码,并且能够带来楼主所说的方便性。尤其是 fstream::fstream 在新版标准中已经经修正能够接受 std::string 参数,说明标准委员会注意到此类的设计失误,在这种情况下,istream::getline 仍然没有支持 string,则必然有其他原因,比较赞同 #7 和 #17 的观点。
[解决办法]
或许确如7楼与17楼所言,出现减少依赖的目的考虑,没有实现basic_istream::getline(basic_string<C,T,A> & )的版本。

不过,fstream不在乎增加依赖,而istream就在乎,似乎也不是很有道理吧……

我还有个猜想:
1:istream中要有char *版本的getline,因为要兼容老代码;
2:istream中是否有string版本的getline,似乎并不重要,getline(std::cin, line)和std::cin.getline(line)相比也没什么不方便的;
3:getline的实现对istream的实现细节依赖不大;
4:如果知道string的具体实现细节,getline或许可以实现得更高效——也许某个库会让string版本的getline成为string的友元。
这样的话,getline与string的关系比它与istream的关系更为紧密,不让它成为istream的成员似乎更合理一些。
[解决办法]
引用:
或许确如7楼与17楼所言,出现减少依赖的目的考虑,没有实现basic_istream::getline(basic_string<C,T,A> & )的版本。

不过,fstream不在乎增加依赖,而istream就在乎,似乎也不是很有道理吧……

看 #12 说的。

引用:
我还有个猜想:


1:istream中要有char *版本的getline,因为要兼容老代码;
2:istream中是否有string版本的getline,似乎并不重要,getline(std::cin, line)和std::cin.getline(line)相比也没什么不方便的;
3:getline的实现对istream的实现细节依赖不大;
4:如果知道string的具体实现细节,getline或许可以实现得更高效——也许某个库会让string版本的getline成为string的友元。
这样的话,getline与string的关系比它与istream的关系更为紧密,不让它成为istream的成员似乎更合理一些。


对,Meyer 提倡能不用成员函数就不用,这样增加封装性。
很可惜没有标准委员会的人能帮咱们印证一下。
[解决办法]

引用:
虽然是在类外部, 但是标准库只有头文件, 没有 cpp, 还是会在头文件之间引入循环包含的.

fstream 可以使用 std::string 了, 那可能是因为 std::string 依赖的是 istream, 而不是 ifstream 所以依赖关系成了:  istream <-- string <-- ifstream 还是能保持单向. 但是要在 istream 的 getline 函数里引入 string 就恼火了, 会造成循环依赖的.


这并不是理由,标准库就算只有头文件(其实是STL只有头文件),不代表它只有<iostream>和<string>之类的头文件,其文件组织比我们看到的要复杂,同样可以把声明和实现分开,写一个forward declaration也很容易,写个简单的例子:

//下面是glad.h
#ifndef __INCLUDE_FILE_GLAD_H___
#define __INCLUDE_FILE_GLAD_H___

#include<iosfwd>
class sad;

class glad
{
public:
    void laugh( std::basic_ostream<char,std::char_traits<char> > & out, sad & other );
    void stop(  std::basic_ostream<char,std::char_traits<char> > & out);
};

#include "glad_impl.h"
#endif
//上面是glad.h

//下面是sad.h
#ifndef __INCLUDE_FILE_SAD_H___
#define __INCLUDE_FILE_SAD_H___

#include<iosfwd>

class glad;
class sad
{
public:
    void cry( std::basic_ostream<char,std::char_traits<char> > & out, glad & other );
};

#include "sad_impl.h"
#endif
//上面是sad.h

//下面是glad_impl.h
#ifndef __INCLUDE_FILE_GLAD_IMPL_H___
#define __INCLUDE_FILE_GLAD_IMPL_H___

#include "glad.h"
#include "sad.h"
#include <iostream>

inline void glad::laugh( std::basic_ostream<char,std::char_traits<char> > & out, sad & other )
{
    out << "我很高兴!我笑,我笑!我再笑!!\n";
    other.cry( out, *this );   
}

inline void glad::stop(  std::basic_ostream<char,std::char_traits<char> > & out)
{
    out <<"我不笑了。\n" ;
}
#endif
//上面是glad_impl.h

//下面是sad_impl.h
#ifndef __INCLUDE_FILE_SAD_IMPL_H___
#define __INCLUDE_FILE_SAD_IMPL_H___

#include "glad.h"
#include "sad.h"
#include <iostream>

inline void sad::cry( std::basic_ostream<char,std::char_traits<char> > & out, glad & other )
{
    out << "我很悲伤,我哭了……\n";
    other.stop(out);  
}


#endif

//上面是sad_impl.h


[解决办法]
引用:
同样的还有 fstream 的构造函数和 open 函数, 都是用 char* 做参数的, 而不是用 std::string, 因为不想引入过多的依赖性.

个人认为是为了遵守0开销原则,因为我们很多是时候在代码中把文件名写成字符串常量,没有必要创建std::string. 对于文件名已经由std::string保存的情况,确实有些不方便,不过也没有什么大不了的。



[解决办法]

引用:
全局的 getline 是定义在 string 头文件里面的.

basic_istream 类是不依赖于 std::string 的, 它都不知道有 std::string 可用, 就只能按传统的字符串方式了.


同意。C++的流的扩展依靠运算符重载(<<, >>)

热点排行