Why does the constructor and open
method of the std::(i|o)fstream classes take the name of a file as a parameter in the form of a const char*
instead of an std::string
? It seems like the creators of the STL would want to use what they had written instead of using the type they wrote a class to replace.

- 129,499
- 52
- 291
- 397

- 73,875
- 22
- 181
- 249
-
2Added `history` tag, as I'm sure there'll be a historical reason behind it. – Xeo May 12 '11 at 00:47
-
2Note that in C++0x file streams now have constructor overloads taking `std::string const&`, so this discussion is *purely* historical. – ildjarn May 12 '11 at 00:54
-
@ildjarn: Good to know, I didn't take a look at the C++0x `std` library yet. :) – Xeo May 12 '11 at 00:56
-
1+1 Really enjoyed reading all the answers and comments on this one. Looked so innocent at first! – idz May 13 '11 at 00:55
5 Answers
The string
part of the library was developed after streams, and nobody thought to make the obvious modifications.
It's merely out of political and temporal reality that they never got around to this before shipping C++98, and nobody bothered bringing it up again because you could always solve it with .c_str()
.
C++0x fixes this (see 27.9.1.6).
Welcome to C++.

- 378,754
- 76
- 643
- 1,055
-
The idea that nobody thought about it back then is plainly wrong. To the contrary, this was extensively discussed in the 90s and later. It's just that, back then, nobody came up with a proposal that turned the opinion of enough people who had a vote in the standardization committee. Probably the most prominent arguments against it back then was that streams should be usable without `
`. I disagreed back then, and still do, but I have to admit that the argument has some merits. – sbi Sep 30 '14 at 11:22 -
@sbi: `s/nobody/no voting member of the committee/` in the answer – Lightness Races in Orbit Sep 30 '14 at 12:13
It's mainly for historical reasons, as far as I know. ifstream
and ofstream
existed long before std::string
. They didn't even have a std::
back then.

- 12,825
- 1
- 29
- 40
-
If this is true, then it is the answer. However, changing the parameter from a `const char*` to `std::string` would not break existing code, because of implicit conversion of one to the other via the `string`'s `const char*` constructor (unless I'm misunderstanding something which is always likely). Why haven't they changed it? – Seth Carnegie May 12 '11 at 00:50
-
-
They had plenty of opportunity, but C++ is designed by committee. (disclaimer: I have friends on the committee. Doesn't change my view.) – Lightness Races in Orbit May 12 '11 at 00:57
-
To the anonymous down-voter. What was your issue? I stated a objective fact: The `ofstream` and `ifstream` existed long before `std::string`. I made plain that a portion of the answer was an opinion "as far as I know". If you are going to down-vote at least have the decency to explain why you felt it was warranted. – idz May 12 '11 at 01:10
-
1@Seth: **changing** the parameter and using the `std::string` constructor implicitly would break binary compatibility with code that had already been compiled. On the other hand, **adding an overload** would be perfectly fine, and has been done in the C++0x standard. – Ken Bloom May 12 '11 at 01:14
-
@idx: I'm not the downvoter, but we **do** downvote incorrect answers around here, even when you try to avoid responsibility for the correctness by hedging your words. We agree that `ifstream` and `ofstream` existed long before `std::string`, but we think that there's a better reason than simply a historical legacy of `std::string` not being present. – Ken Bloom May 12 '11 at 01:15
-
@Tomalak In his answer Ken Bloom makes what may explain why they never "retrofitted" `iostreams`. – idz May 12 '11 at 01:19
-
@Ken thanks for the explanation. Though still think that an anonymous down-vote does little to move the discussion forward. – idz May 12 '11 at 01:28
-
@idz: this isn't (really) a discussion site, that we need to move the discussion forward. People post answers. People vote. The best answer wins. – Ken Bloom May 12 '11 at 01:38
-
@Ken Bloom: Isn't the STL code generated at compile time? How would changing a parameter break binary compatibility with code already compiled? I thought the code for (o|i)fstream resided inside the binary itself. – Seth Carnegie May 12 '11 at 13:49
-
@Seth: Not necessarily; an implementation is totally free to define _Standard Library_ symbols inside its runtime, and to statically link that runtime. And whether it does or not, you _still_ have to consider compatibility between two object files that you link together. – Lightness Races in Orbit Jul 19 '13 at 12:50
Class std::string
implements the concept of "run-time-sized resizable string". This is when this class should be used - when you need a string whose size is only known at run-time and which is run-time resizable as well. In situations when you don't need these features using std::string
is an overkill. Apparently, the authors of the library didn't think that they needed a run-time resizable string to represent a file name, so they opted for a minimalistic solution: they used a C-string where a C-string was sufficient. This is actually a very good principle for designing library interfaces: never require something that you don't really need.
It is true that these days we often see people who encourage C++ programmers to use std::string
whenever they need a string, any string. They often claim that classic C strings should be reserved to C code. In general case this is a bogus philosophy. Gratuitous use of comparatively heavy objects like std::string
is more appropriate in languages like Java, but is normally unacceptable in C++.
Yes, it is possible to get away with using std::string
all the time in some C++ applications ("it is possible to write a Java program in C++"), but in such a generic low-level library as C++ standard library forcing the user to use std::string
without a good reason (i.e. imposing unnecessary requirements) would not look good.

- 312,472
- 42
- 525
- 765
-
1Your last paragraph makes no sense. They could just have provided overloads for `std::string` and `const chat*`. – Xeo May 12 '11 at 00:57
-
1It doesn't need a resizable string to open a file, so it doesn't take one. C++ has a long-standing mantra of "Don't pay for what you don't need", so this fits pretty well. – Cory Nelson May 12 '11 at 00:58
-
9Nonsense. There was and is no practical reason not to do it; it's simply that politics and time schedules got in the way of applying `std::string` to the STL-inherited stream features before C++98 shipped, and they never bothered to update it. I don't know off-hand whether C++0x fixes this; I don't believe that it does. – Lightness Races in Orbit May 12 '11 at 00:58
-
2@Xeo: I agree that providing an overload that would take a `c_str()` from the `std::string` and pass it to the C-string version of the function would make sense. – AnT stands with Russia May 12 '11 at 00:59
-
2You often need to build up a pathname at run-time. Seems like `std::string` would be quite appropriate. You said "the authors of the library didn't think that they need a run-time resizable string to represent a file name" do you have a reference for that or is that speculation? – idz May 12 '11 at 01:00
-
1I don't think the problem is "forcing the user to use `std::string`" I think it's that they didn't want to increase the size of the binary and increase the compilation time by forcing the compiler to include `std::string` stuff if the user isn't going to use `std::string`. – Ken Bloom May 12 '11 at 01:10
-
@idz: so if you need to build up the pathname at runtime, then you use `std::string` and you convert using `.c_str()` when you want to open a file with that path. (Not that I agree with the decision, I'm just trying to present a reason why they probably didn't feel your justification was worthwhile.) – Ken Bloom May 12 '11 at 01:21
-
@Ken In understand that. I was responding the responder's assertion that it somehow had to do with appropriateness of the type. – idz May 12 '11 at 01:39
-
1Do you have a citation for this answer? Is this what the *standards committee* thought, or is this your personal speculation/rationalization? – John Kugelman May 12 '11 at 01:55
-
@idz: While the wording I used does indeed imply a personal opinion, in any case the fact that the stream functions do not need any features of `std::string` (as compared to features of C-string) in that specific place is just that - a fact, and a rather obvious one. And as I said before, it would make sense to provide the overloaded dual interface that would support both C-strings and `std::string`. I'm surprised it wasn't done. – AnT stands with Russia May 13 '11 at 00:36
-
@idz: However, one the other hand, the moment the C++ standard library will start *forcing* the user to use `std::string` where ordinary C-string is perfectly sufficient is exactly the moment the C++ standard library will make a loud *plonk* sound by hitting the shiny metal bottom of the garbage bin of history. C++ is not Java and will never be (or so I hope). I'm glad at least authors of Boost understand that well. – AnT stands with Russia May 13 '11 at 00:37
-
@AndreyT thanks for the answer, I wasn't trying to be provocative I really wanted to know if anyone knew why the committee made their decision. Another responder said that he knew one of the committee and the time and political pressure was to blame. To keep `iostreams` and `STL` separate does seem like a plausible argument, until they both became part of the "C++ Standard Library". I agree with you, an overloaded dual interface would be preferable. It would be nice to have the option. – idz May 13 '11 at 00:48
-
@AndreyT: Why would it ever do that? It could [and should] have an overload for `char const*` and an overload for `std::string const&`. Fortunately, this is exactly what C++0x does (27.9.1.6). – Lightness Races in Orbit Aug 05 '11 at 17:38
-
2I agree with this answer's opinion. But from what I hear, the committee didn't have this rationale. It was just overlooked. – Johannes Schaub - litb Aug 06 '11 at 13:53
-
I usually try to avoid std::string as a parameter in my function signatures and use "const char*" instead. The reason is simple : the client of my code might not be using std::string as their string class. They might be using Qt or some other library. I don't want them to have to pay the cost of converting their QString object for example to a std::string, which will get thrown away anyway after the function call. The standard commitee might have decided against using std::string in method signatures just for that reason. Obviously, std::string as a return parameter is just fine tough. – fronsacqc Dec 06 '11 at 21:17
-
`Gratuitous use of comparatively heavy objects like std::string is more appropriate in languages like Java, but is normally unacceptable in C++` What's unacceptable is that people run around pretending like these objects are "heavy", when they are not! Don't confuse member functions for member data. You're spreading dangerous misinformation. – Lightness Races in Orbit Jul 19 '13 at 12:33
-
1The way to pass non-resizable sequences that puts the least requirements on the interface is neither to take a `std::string` nor a `const chat*`, but to take a pair of iterators. – R. Martinho Fernandes Jul 19 '13 at 12:38
-
@Johannes: This wasn't overlooked. I remember discussions about it on `clc++m` in the 90s. – sbi Sep 30 '14 at 11:40
-
Assuming file names are always constant string literals is arbitrary and weird. Actually I'm writing many programs that generate the file name at run time. – jiandingzhe Oct 09 '14 at 01:34
-
@jiandingzhe: Er... Declaring a function with `const char *` parameter does not in any way convey the idea that its argument is supposed to be a "constant string literal". So far nobody mentioned "constant string literals". How did you manage to jump to such a genuinely weird conclusion is unclear to me. Care to elaborate? – AnT stands with Russia Oct 09 '14 at 02:14
-
@AndreyT: Sorry I didn't make a clear description. The first sentence of this answer is "Class `std::string` implements the concept of "run-time-sized resizable string"", and I'm declaring that the file name can probably be generated at run-time. As a result, it's better that file handle can accept `std::string` as its argument. I hate typing `.c_str()` everytime. – jiandingzhe Oct 11 '14 at 03:11
My bet is that the iostream
hierarchy / library (including (i|o)fstream
) was invented / developed apart from std::string
, and they only first met when put together in the std
library.
At the time of invention of iostream
, there were maybe many different string
implementations going around and to support maximum portability, they decided to bet on a data type that's always available, and that's a simple char const*
c-style string.

- 129,499
- 52
- 291
- 397
Just looking through my G++'s <fstream>
header, I noticed that all of the references to std::basic_string
or any of its typedefs
are in sections delimited with #ifdef __GXX_EXPERIMENTAL_CXX0X__
.
This suggests to me that the iostreams library was designed to be independent of the string library, so that if you didn't use std::string
, you didn't have to pay for it (this has historically been a very important design principle in C++). This would also explain why getline(std::istream&, std::string&)
is a free function defined in <string>
, rather than a member function like istream::getline(char*, streamsize)
.
This also suggests to me in the C++0x standardization viewed this as a design flaw, and decided that the inconvenience of making the iostreams library independent of the string library just wasn't worth it.
(I can't be bothered to go find a working draft of the C++0x spec, or systematically check all of the iostreams related headers to confirm any of this.)

- 57,498
- 14
- 111
- 168
-
Here, now you can be bothered ;-] http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2011/n3290.pdf – ildjarn May 12 '11 at 01:36