What is the C++ standard library equivalent for mkstemp?
Asked Answered
H

3

12

I am transitioning a program that uses temporary files from POSIX FILE to C++ standard library iostreams. What's the correct alternative to mkstemp?

Haag answered 15/10, 2011 at 15:56 Comment(3)
Not sure about iostreams, but there is always tmpnamWadai
@DavidHeffernan tmpnam is indeed a good alternative if you can ignore the (small) risk of a file with that name being created in between.Bon
the STL is not the same thing as the C++ standard library. STL is commonly used to refer to the containers, iterators and algorithms components of the C++ standard library. IOStreams is not really part of the STL, and the STL doesn't need to have an equivalent for every part of the C standard library (which is also available in C++), or for various POSIX functionsNatie
L
4

There is no portable C++ way to do it. You need to create a file (which is done automatically when opening a file for writing using an ofstream) and then remove it again when you're finished with the file (using the C library function remove). But you can use tmpnam to generate a name for the file:

#include <fstream>
#include <cstdio>

char filename[L_tmpnam];
std::tmpnam(filename);
std::fstream file(filename);
...
std::remove(filename);   //after closing, of course, either by destruction of file or by calling file.close()
Lisette answered 15/10, 2011 at 16:7 Comment(2)
This is unfortunate. Isn't there a way to open a stream from an already existing open fd?Haag
@Haag CatPlusPlus has a boost solution to do that, but if you don't want to use boost (like you said in your comment), then there won't be a portable way to create a stream from a file descriptor, I think.Lisette
J
6

There is none. Note that mkstemp is not part of either C (C99, at least) or C++ standard — it's a POSIX addition. C++ has only tmpfile and tmpnam in the C library part.

Boost.IOStreams, however, provides a file_descriptor device class, which can be used to create a stream operating on what mkstemp returns.

If I recall correctly, it should look like this:

namespace io = boost::iostreams;

int fd = mkstemp("foo");
if (fd == -1) throw something;

io::file_descriptor device(fd);
io::stream<io::file_descriptor> stream(device);

stream << 42;
Jiggle answered 15/10, 2011 at 16:4 Comment(2)
Again, unfortunate. I don't want to use boost.Haag
@vy32: That's silly. Boost is de facto a second standard library in C++. Avoiding it is counter-productive. AFAIK IOStreams doesn't have too many dependencies, so you can include it with your code if you don't want people to download it separately.Jiggle
P
5

If you want a portable C++ solution, you should use unique_path in boost::filesystem :

The unique_path function generates a path name suitable for creating temporary files, including directories. The name is based on a model that uses the percent sign character to specify replacement by a random hexadecimal digit. [Note: The more bits of randomness in the generated path name, the less likelihood of prior existence or being guessed. Each replacement hexadecimal digit in the model adds four bits of randomness. The default model thus provides 64 bits of randomness. This is sufficient for most applications

Pieria answered 15/10, 2011 at 17:23 Comment(3)
Thanks. But I don't want to use boost. It's not built in to my compiler, and I don't want to require people using my source code to download boost.Haag
Boost's unique_path is as bad as std::tmpnam due to the race it leads to.Mildew
This doesn't change any of the issues tmpnam has: just tmpnam properly warns you of potential data races while this does not. You need to open(O_EXCL), or you need another way to ensure there are no races.Sargeant
L
4

There is no portable C++ way to do it. You need to create a file (which is done automatically when opening a file for writing using an ofstream) and then remove it again when you're finished with the file (using the C library function remove). But you can use tmpnam to generate a name for the file:

#include <fstream>
#include <cstdio>

char filename[L_tmpnam];
std::tmpnam(filename);
std::fstream file(filename);
...
std::remove(filename);   //after closing, of course, either by destruction of file or by calling file.close()
Lisette answered 15/10, 2011 at 16:7 Comment(2)
This is unfortunate. Isn't there a way to open a stream from an already existing open fd?Haag
@Haag CatPlusPlus has a boost solution to do that, but if you don't want to use boost (like you said in your comment), then there won't be a portable way to create a stream from a file descriptor, I think.Lisette

© 2022 - 2024 — McMap. All rights reserved.