Looking around other answers on stackoverflow the answer may just be a no, but please humor me before marking it a duplicate.
So I want to be able for format a string snprintf style as shown below, but only make a single heap allocation.
Lots of examples say to touch the std::String::data() or std::String::c_str() but obviously you shouldn't do this as it's really unsafe, as this is managed memory, so references and pointers are not guaranteed to be constant memory addresses.
Also cannot use std::format as I'm not running C 20
#include <cstdlib>
#include <iostream>
#include <string>
#include <cstdarg>
#include <cstdio>
std::string Somefunction(const char* formatstring, ...){
//Let's get the actual size, because recursively reallocating to get this is not efficient
va_list sizeVl;
va_start(sizeVl, formatstring);
const int formatSize = _vscprintf(formatstring, sizeVl);
va_end(sizeVl);
if (formatSize < 1){
return{};
}
//Some object to put the memory on the stack, I'll use a char, but could be vector<char> etc,
//whatever achieves the goal
char* tempString = new char[formatSize 1];
va_list vl;
va_start(vl, formatstring);
const int actualLength = vsnprintf(tempString, formatSize, formatstring, vl);
va_end(vl);
if (actualLength <= formatSize){
tempString[actualLength] = '\0';
//vv--- I really don't want to reallocate on the heap, I already have some heap memory
//vv--- Move semantics 101
//std::string output = MOVE(tempString);
std::string output("Ideally I move the memory here");
return output;
}
delete[] tempString;
return{};
}
Any thoughts, or is the answer really just std::string isn't the container for you if you want this functionality?
Is there any container I can use safely as a char array in the vsnprintf function that std::String will move safely?
CodePudding user response:
The comments in your question are correctly directing you to instantiate a string with a specific size and use the .data()
or &[0]
operator to get what you need.
Let me suggest a simpler solution with a constraint. Consider that your output strings have some reasonable length and that you have plenty of stack memory to work with. So use a fixed length temp buffer to do your printf style formatting. 20K is not an unreasonable number of bytes to allocate on the stack.
Then return an instance of a std::string
using the copy from C string constructor at the very end.
std::string Somefunction(const char* formatstring, ...){
const size_t TEMP_SIZE = 20000;
va_list vargs = {};
va_start(vargs, formatstring);
char buffer[TEMP_SIZE];
vsnprintf(buffer, TEMP_SIZE, formatstring, vargs);
va_end(vargs);
return std::string(buffer);
}
You could always increase the buffer size from 20000 to something larger if you needed it. But I'm guessing your strings never get that big. And if they did, you wouldn't want that many bytes in what I'm guessing is your log file.