C++ - 给 std::string 赋值为 null

49

我正在自学C++。我有以下代码,但是它会报错。

#include <iostream>
#include <string>
using namespace std;


int setvalue(const char * value)
{
    string mValue;
    if(value!=0)
    {
       mValue=value;
    }
    else
    {
       mValue=0;
    }
}

int main ()
{
 const char* value = 0;
 setvalue(value);

 cin.get();
 return 0;
}

想创建一个接受char指针的函数,并将指向它的指针传递给该函数。该函数将指针赋值给其成员变量。我有意传递了一个空指针。以下是我遇到的错误:

 D:\CPP\TestCP.cpp In function `int setvalue(const char*)': 

 note C:\Dev-Cpp\include\c++\3.4.2\bits\basic_string.h:422 candidates are: std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 

 note C:\Dev-Cpp\include\c++\3.4.2\bits\basic_string.h:422                 std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(const _CharT*) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 

 note C:\Dev-Cpp\include\c++\3.4.2\bits\basic_string.h:422                 std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(_CharT) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 

它基本上是在抱怨这一行代码: mValue=0;

为什么会对这行代码抱怨呢?我不能将 null 赋值给一个 String 吗?


3
你将它设为0,是为了达成什么目的? - James M
这个函数的目的是将传递给该函数的char*分配给它的成员字符串变量。因此,我首先检查它是否为空,如果为空,则将null分配给String而不是引用null指针。所以,目的是让mValue和Value包含类似的值。谢谢。 - Maria
1
但是如果value是一个空指针, mValue = value; 将只是执行 mValue = 0; ,如果 mValue = 0; 是有效的话,那么多余的检查实际上没有任何作用。它同样是无效的。 - user743382
如果您想区分空字符串和无字符串,可以考虑使用boost::optional - chris
@Maria - 你不能仅凭自己尝试学习C++,你需要一本好书。此外,gcc 3.4.2已经非常老旧,不再是一个好的编译器。 - Bo Persson
可能是如何允许std:string参数为空?的重复问题。 - krlmlr
8个回答

84
我不能将null赋给一个字符串吗?
不行。std :: string不是指针类型;它不能变为“null” 。它不能表示缺少值,这就是空指针用于表示的内容。
可以通过将空字符串赋给它(s =“”或s = std :: string())或清除它(s.clear())使其为空。

6
请注意,使用NULL0会导致编译错误。然而,使用nullptr则可以通过编译,因为它不是int类型,赋值操作符会选择char*类型。不过,在运行时会发生错误。 - Zitrax

20

在C ++中,您不能将 NULL 0 赋值给 std :: string 对象,因为该对象不是指针。这是与C风格字符串的一个关键区别; C风格字符串可以是 NULL 或有效的字符串,而C ++ std :: string 始终存储某些值。

没有简单的解决方法。如果您想保留哨兵值(例如,空字符串),则可以执行以下操作:

const std::string NOT_A_STRING = "";

mValue = NOT_A_STRING;

或者,您可以存储一个字符串指针,以便将其设置为 null:

std::string* mValue = NULL;

if (value) {
    mValue = new std::string(value);
}

希望这可以帮到您!


mValue=new std::string(value); 出现错误:11 D:\CPP\TestCP.cpp 无效的从 std::string*' 到 char' 的转换 11 D:\CPP\TestCP.cpp 初始化参数 1 时出错,使用了 `std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(_CharT) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]' - Maria
1
@Maria- 你把 mValue 的声明从 string myValue 改成了 string* myValue 吗? - templatetypedef
不,我不想它成为一个指针。我能这样做吗:minValue =(char *)0? - Maria
4
@Maria:不可以。这是未定义的行为。无论如何,你期望它意味着什么?你已经被告知不能有一个空字符串了。 - Benjamin Lindley

7

字面量0属于int类型,你无法将int赋值给std::string。使用mValue.clear()或者赋值一个空字符串mValue=""


不是你说的不对,而是那并不能解释出问题所在。 - user743382
这并不一定有效;在这里,NULL可能被用作哨兵。C字符串允许你区分空字符串和NULL字符串;而C++字符串则不行。 - templatetypedef
空字符串和null不是同一个东西。我不能将null赋值给字符串? - Maria
@Maria:不,0int 类型,但空字符串字面值 ""char const * 类型(指向常量字符的指针)。这是两种完全不同的类型。 - Juraj Blaho
@JurajBlaho,实际上它是一个const char[] - chris
@chris:没错。无论如何它都可以被隐式转换为指针。 - Juraj Blaho

5
我不会争论这是一个好主意(或者在非指针类型中使用nullptr的语义),但是创建一个类来提供“可空”语义(请参见nullable_string)相对简单。
然而,这更适合于C++17的std::optional
#include <string>
#include <iostream>
#include <optional>

// optional can be used as the return type of a factory that may fail
std::optional<std::string> create(bool b)
{
    if (b)
        return "Godzilla";
    else
        return {};
}

int main()
{
    std::cout << "create(false) returned "
              << create(false).value_or("empty") << std::endl;

    // optional-returning factory functions are usable as conditions of while and if
    if (auto str = create(true))
    {
        std::cout << "create(true) returned " << *str << std::endl;
    }
}

std::optional,如示例所示,可转换为bool,或者您可以使用has_value()方法,有针对错误访问的异常等。这为您提供了可空语义,似乎是Maria试图实现的目标。

如果您不想等待C++17兼容性,则可以查看关于Boost.Optional的此答案


5
有两种方法可以处理指向C风格字符串的空指针,它们可以达到相同的效果。
三目运算符。
void setvalue(const char *value)
{
    std::string mValue = value ? value : "";

}

或者谦卑的if语句
void setvalue(const char *value)
{
    std::string mValue;
    if(value) mValue = value;

}

在这两种情况下,只有在value不为null指针时,mValue才会被赋值。而在其他所有情况下(即当value为null指针时),mValue将包含一个空字符串。
三目运算符方法可能适用于在没有value的情况下提供备用默认字符串字面值:
std::string mValue = value ? value : "(NULL)";

4
需要检查空指针并进行有条件的分配是为了避免使用空指针初始化/分配std::string会导致未定义的行为,因此应该尽量避免。 - underscore_d
@underscore_d 很棒的评论。你救了我的一天。 :) - hellodear

1

else情况是不必要的,当你创建一个string对象时,默认情况下它是空的。


0
编译器会报错,因为当赋值mValue=0时,编译器找到了int类型的赋值运算符=(int )用于编译时绑定,但是在string类中并不存在该运算符。 如果我们将以下语句强制转换为char类型,如mValue=(char)0,则可以成功编译,因为string类包含operator=(char)方法。

-1

许多C API使用空指针来表示“使用默认值”,例如mosquittopp。这里是我正在使用的模式,基于David Cormack的答案:

    mosqpp::tls_set(
        MqttOptions->CAFile.length() > 0 ? MqttOptions->CAFile.c_str() : NULL,
        MqttOptions->CAPath.length() > 0 ? MqttOptions->CAPath.c_str() : NULL,
        MqttOptions->CertFile.length() > 0 ? MqttOptions->CertFile.c_str() : NULL,
        MqttOptions->KeyFile.length() > 0 ? MqttOptions->KeyFile.c_str() : NULL
    );

这可能有点繁琐,但可以让你一直使用std::string,直到 API 调用本身。


你可以很容易地添加一个内联工具方法来实现相同的功能。char const* c_str(std::string const &s) { return s.length() > 0 ? s.c_str() : nullptr; } 用法:mosqpp::tls_set(c_str(MqttOptions->CAFile), c_str(MqttOptions->CAPath), c_str(MqttOptions->CertFile), c_str(MqttOptions->KeyFile)); - monkey0506

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接