在C ++中有没有更优雅的方式将sprintf和std :: string结合起来?

时间:2015-06-26 02:47:17

标签: c++ string c++11 printf string-formatting

在我的C ++代码中经常使用以下类型的辅助函数:

static inline std::string stringf(const char *fmt, ...)
{
    std::string ret;
    // Deal with varargs
    va_list args;
    va_start(args, fmt);
    // Resize our string based on the arguments
    ret.resize(vsnprintf(0, 0, fmt, args));
    // End the varargs and restart because vsnprintf mucked up our args
    va_end(args);
    va_start(args, fmt);
    // Fill the string
    if(!ret.empty())
    {
        vsnprintf(&ret.front(), ret.size() + 1, fmt, args);
    }
    // End of variadic section
    va_end(args);
    // Return the string
    return ret;
}

它有一些好处:

  1. 字符串长度没有任意限制
  2. 该字符串是就地生成的,不会被复制(如果RVO正常工作)
  3. 外界没有惊喜
  4. 现在,我遇到了一些问题:

    1. 重新扫描varargs的丑陋
    2. 事实上,std :: string在内部是一个连续的字符串,后面直接有一个空终结符的空格,但实际上并没有在规范中明确说明。它的含义是 - > c_str()必须是O(1)并返回一个以空字符结尾的字符串,我相信&(data()[0])应该等于& (*开头())
    3. vsnprintf()被调用两次,可能是第一次进行昂贵的丢弃工作
    4. 有人知道更好的方法吗?

3 个答案:

答案 0 :(得分:5)

你结婚了(双关语)std::sprintf()?如果您正在使用C ++和现代std::string,为什么不充分利用新的语言功能并使用可变参数模板来执行返回sprintf的类型安全std::string

看看这个非常好看的实现:https://github.com/c42f/tinyformat。我想这可以解决你所有的问题。

答案 1 :(得分:3)

当您添加标记c++11时,我认为您可以使用它。然后,您可以将代码简化为:

namespace fmt {

template< class ...Args >
std::string sprintf( const char * f, Args && ...args ) {
    int size = snprintf( nullptr, 0, f, args... );
    std::string res;
    res.resize( size );
    snprintf( & res[ 0 ], size + 1, f, args... );
    return res;
}

}

int main() {
    cout << fmt::sprintf( "%s %d %.1f\n", "Hello", 42, 33.22 );
    return 0;
}

http://ideone.com/kSnXKj

答案 2 :(得分:1)

不要使用大小为0的第一个$ ./bin/getline_rdfile dat/damages.txt Lines in file: array [ 0] Personal injury damage awards are unliquidated array [ 1] and are not capable of certain measurement; thus, the array [ 2] jury has broad discretion in assessing the amount of array [ 3] damages in a personal injury case. Yet, at the same array [ 4] time, a factual sufficiency review insures that the array [ 5] evidence supports the jury's award; and, although array [ 6] difficult, the law requires appellate courts to conduct array [ 7] factual sufficiency reviews on damage awards in array [ 8] personal injury cases. Thus, while a jury has latitude in array [ 9] assessing intangible damages in personal injury cases, array [ 10] a jury's damage award does not escape the scrutiny of array [ 11] appellate review. array [ 12] array [ 13] Because Texas law applies no physical manifestation array [ 14] rule to restrict wrongful death recoveries, a array [ 15] trial court in a death case is prudent when it chooses array [ 16] to submit the issues of mental anguish and loss of array [ 17] society and companionship. While there is a array [ 18] presumption of mental anguish for the wrongful death array [ 19] beneficiary, the Texas Supreme Court has not indicated array [ 20] that reviewing courts should presume that the mental array [ 21] anguish is sufficient to support a large award. Testimony array [ 22] that proves the beneficiary suffered severe mental array [ 23] anguish or severe grief should be a significant and array [ 24] sometimes determining factor in a factual sufficiency array [ 25] analysis of large non-pecuniary damage awards. 。而是使用具有一些可能大小的堆栈缓冲区(例如64到4096之间的东西),如果适合,则将其复制到返回值中。

您对$ valgrind ./bin/getline_rdfile dat/damages.txt ==14321== Memcheck, a memory error detector ==14321== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al. ==14321== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info ==14321== Command: ./bin/getline_rdfile dat/damages.txt ==14321== Lines in file: array [ 0] Personal injury damage awards are unliquidated <snip> ... array [ 25] analysis of large non-pecuniary damage awards. ==14321== ==14321== HEAP SUMMARY: ==14321== in use at exit: 0 bytes in 0 blocks ==14321== total heap usage: 29 allocs, 29 frees, 3,997 bytes allocated ==14321== ==14321== All heap blocks were freed -- no leaks are possible ==14321== ==14321== For counts of detected and suppressed errors, rerun with: -v ==14321== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2) 邻居的担忧是错误的。它是明确的,完全可以依赖。

最后 - 我想回顾一下编译时格式检查库会更好。你需要C ++ 14才能获得全部功能,但是C ++ 11支持足够多,你应该能够vsnprintf一些头代码而不会丢失任何表达。请记住考虑std::string