如何干净地使用:const char* 和 std::string?

syd*_*dan 5 c++ string concatenation char

电话:博士

我怎么可以连接const char*std::string,整齐而优雅,没有多个函数调用。理想情况下,在一个函数调用中,输出为const char*. 这是不可能的,什么是最佳解决方案?

初始问题

到目前为止,我在 C++ 中遇到的最大障碍是它如何处理字符串。在我看来,在所有广泛使用的语言中,它处理字符串的能力最差。我见过其他与此类似的问题,这些问题的答案要么是“使用std::string”,要么只是指出其中一个选项最适合您的情况。

然而,当尝试像在其他语言中那样动态地使用字符串时,这是无用的建议。我不能保证总是能够使用,std::string并且在我必须使用的时候,const char*我碰到了“它是恒定的,你不能连接它”的明显墙。

我在 C++ 中看到的任何字符串操作问题的每个解决方案都需要重复的多行代码,这些代码仅适用于该字符串格式。我希望能够将任何字符集与+符号连接起来,或者像format()在 C# 或 Python 中一样使用一个简单的函数。为什么没有简单的选择?

现在的情况

标准输出

我正在编写一个 DLL,到目前为止我已经cout通过<<操作符输出了文本。到目前为止,使用以下形式的简单字符数组一切正常:

cout << "Hello world!"
Run Code Online (Sandbox Code Playgroud)

运行时字符串

现在到了我想在运行时构造一个字符串并将其与一个类一起存储的点,这个类将保存一个报告一些错误的字符串,以便其他类可以获取它们并可能cout稍后发送给字符串将由函数设置SetReport(const char* report)。所以我真的不想为此使用多于一行,所以我继续写一些类似的东西:

SetReport("Failure in " + __FUNCTION__ + ": foobar was " + foobar + "\n"); // __FUNCTION__ gets the name of the current function, foobar is some variable
Run Code Online (Sandbox Code Playgroud)

当然,我立即得到:

  • expression must have integral or unscoped enum type 和...
  • '+': cannot add two pointers

丑陋的弦

对。所以我试图将两个或更多const char*s添加在一起,但这不是一个选择。所以我发现这里的主要建议是使用std::string,有点奇怪,打字"Hello world!"不仅首先给你一个,但让我们试一试:

SetReport(std::string("Failure in ") + std::string(__FUNCTION__) + std::string(": foobar was ") + std::to_string(foobar) + std::string("\n"));
Run Code Online (Sandbox Code Playgroud)

杰出的!有用!但你看那有多丑!!这是我见过的最丑陋的代码之一。我们可以简化为:

SetReport(std::string("Failure in ") + __FUNCTION__ + ": foobar was " + std::to_string(foobar) + "\n");
Run Code Online (Sandbox Code Playgroud)

仍然可能是我每次遇到的最糟糕的方式来进行简单的单行字符串连接,但现在一切都应该没问题吧?

转换回常数

好吧,不,如果你正在处理一个 DLL,我倾向于做很多事情,因为我喜欢单元测试,所以我需要我的 C++ 代码由单元测试库导入,当你尝试设置时,你会发现将字符串报告给类的成员变量作为std::string编译器抛出警告说:

warning C4251: class 'std::basic_string<_Elem,_Traits,_Alloc>' needs to have dll-interface to be used by clients of class'
Run Code Online (Sandbox Code Playgroud)

除了“忽略警告”(不好的做法!)之外,我发现这个问题的唯一真正解决方案是const char*用于成员变量而不是std::string但这并不是真正的解决方案,因为现在您必须转换丑陋的连接(但动态)字符串返回到您需要的 const char 数组。但是你不能只.c_str()在最后标记(即使你为什么想要因为这种连接在第二个变得更加荒谬?)你必须确保std::string不会清理你新构建的字符串并给你留下垃圾. 因此,您必须在接收字符串的函数中执行此操作:

const std::string constString = (input);
m_constChar = constString.c_str();
Run Code Online (Sandbox Code Playgroud)

这太疯狂了。因为现在我遇到了几种不同类型的字符串,使我的代码变得丑陋,添加了比需要的更多的行,而所有这些都只是为了将一些字符粘在一起。为什么这么难?

解决方案?

那么有什么解决办法呢?我觉得我应该能够制作一个将const char*s连接在一起的函数,但也可以处理其他对象类型,例如std::string, intor double,我强烈认为这应该可以在一行中完成,但我找不到任何示例正在实现。我应该使用char*而不是常量变量,即使我已经读过你永远不应该改变的值,char*那么这有什么帮助?

有没有经验丰富的 C++ 程序员解决了这个问题,现在对 C++ 字符串很满意,你的解决方案是什么?没有解决办法吗?不可能吗?

tiv*_*ivn 1

最简单的解决方案之一是使用C++ 空字符串。在这里,我声明了名为 name 的空字符串变量_,并在字符串连接前面使用它。确保始终将其放在前面。

#include <cstdio>
#include <string>

using namespace std;
string _ = "";

int main() {
        char s[] = "chararray";
        string result =
                _ + "function name = [" + __FUNCTION__ + "] "
                "and s is [" + s + "]\n";
        printf( "%s", result.c_str() );
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

function name = [main] and s is [chararray]
Run Code Online (Sandbox Code Playgroud)

关于__FUNCTION__,我发现在 Visual C++ 中它是一个宏,而在 GCC 中它是一个变量,因此SetReport("Failure in " __FUNCTION__ "; foobar was " + foobar + "\n");仅适用于 Visual C++。请参阅: https: //msdn.microsoft.com/en-us/library/b0084kay.aspxhttps://gcc.gnu.org/onlinedocs/gcc/Function-Names.html

上面使用空字符串变量的解决方案应该适用于 Visual C++ 和 GCC。