53

I am learning C++ on my own. I have the following code but it gives error.

#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;
}

So want to create a function which accepts char pointers and I want to pass a pointer to it. The function assigns the pointer to its member variable. I'm passing a null pointer intentionally. Following is the error I'm getting:

 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>] 

it's basically complaining about line: mValue=0;

Why is it complaining about this line? I can't assign a null to a String?

6
  • 3
    What are you trying to accomplish by setting it to 0? Commented Jul 23, 2012 at 17:38
  • The purpose of the function is to take the char* passed to the function and assign it to it's member string variable. So I'm checking first if it is null, if it is null, then instead of dereferencing a null pointer, I'm assigning null to String. So the purpose is to have mValue and Value to contain similar values. Thanks. Commented Jul 23, 2012 at 17:41
  • 1
    But mValue = value; would just do mValue = 0; when value is a null pointer, if mValue = 0; were valid, so the extra check doesn't really do anything. It would be just as invalid. Commented Jul 23, 2012 at 17:43
  • You might want to look into boost::optional if you're set on distinguishing between an empty string and no string. Commented Jul 23, 2012 at 17:47
  • @Maria - You cannot learn C++ by trying it out by yourself, you need a good book. Also gcc 3.4.2 is not a good compiler anymore, it is very old. Commented Jul 23, 2012 at 18:40

8 Answers 8

89

I can't assign a null to a String?

No. std::string is not a pointer type; it cannot be made "null." It cannot represent the absence of a value, which is what a null pointer is used to represent.

It can be made empty, by assigning an empty string to it (s = "" or s = std::string()) or by clearing it (s.clear()).

Sign up to request clarification or add additional context in comments.

1 Comment

Note that you get the compile error with NULL or 0. However using nullptr compiles since it's not an int and the assignment operator for char* is chosen. It will error at runtime though.
20

You cannot assign NULL or 0 to a C++ std::string object, because the object is not a pointer. This is one key difference from C-style strings; a C-style string can either be NULL or a valid string, whereas C++ std::strings always store some value.

There is no easy fix to this. If you'd like to reserve a sentinel value (say, the empty string), then you could do something like

const std::string NOT_A_STRING = "";

mValue = NOT_A_STRING;

Alternatively, you could store a pointer to a string so that you can set it to null:

std::string* mValue = NULL;

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

Hope this helps!

4 Comments

mValue=new std::string(value); gives error: 11 D:\CPP\TestCP.cpp invalid conversion from std::string*' to char' 11 D:\CPP\TestCP.cpp initializing argument 1 of `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- Did you change the declaration of mValue from string myValue to string* myValue?
no, I don't want it to be a pointer. Can I do this: minValue = (char*)0 ?
@Maria: No you cannot. It is undefined behavior. What would you expect it to mean anyway? You've already been told you can't have a null string.
7

Literal 0 is of type int and you can't assign int to std::string. Use mValue.clear() or assign an empty string mValue="".

6 Comments

Not that you aren't right, but that doesn't explain what's wrong.
This doesn't necessarily work; NULL might be used as a sentinel here. C strings let you distinguish between empty and NULL strings; C++ strings don't.
empty string and null are not the same. I can't assign Null to string?
@Maria: No, 0 is of type int, but empty string literal "" is of type char const * (a pointer to constant char). That are two completely different types.
@JurajBlaho, It's a const char[], actually.
|
5

There are two methods to consider which achieve the same effect for handling null pointers to C-style strings.

The ternary operator

void setvalue(const char *value)
{
    std::string mValue = value ? value : "";

}

or the humble if statement

void setvalue(const char *value)
{
    std::string mValue;
    if(value) mValue = value;

}

In both cases, value is only assigned to mValue when value is not a null pointer. In all other cases (i.e. when value is null), mValue will contain an empty string.

The ternary operator method may be useful for providing an alternative default string literal in the absence of a value from value:

std::string mValue = value ? value : "(NULL)";

2 Comments

To be clear, the reason to check for null and conditionally assign like this is because initialising/assigning an std::string from a null pointer causes undefined behaviour and thus should be avoided at all costs.
@underscore_d Awesome comment. You saved my day. :)
5

I won't argue that it's a good idea (or the semantics of using nullptr with things that aren't pointers), but it's relatively simple to create a class which would provide "nullable" semantics (see nullable_string).

However, this is a much better fit for C++17's 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, as shown in the example, is convertible to bool, or you may use the has_value() method, has exceptions for bad access, etc. This provides you with nullable semantics, which seems to be what Maria was trying to accomplish.

And if you don't want to wait around for C++17 compatibility, see this answer about Boost.Optional.

Comments

1

The else case is unncecessary, when you create a string object it is empty by default.

Comments

0

compiler gives error because when assigning mValue=0 compiler find assignment operator=(int ) for compile time binding but it's not present in the string class. if we type cast following statement to char like mValue=(char)0 then its compile successfully because string class contain operator=(char) method.

Comments

-1

Many C APIs use a null pointer to indicate "use the default", e.g. mosquittopp. Here is the pattern I am using, based on David Cormack's answer:

    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
    );

It is a little cumbersome, but allows one to keep everything as a std::string up until the API call itself.

1 Comment

You could very easily add an inlined utility method to accomplish the same. char const* c_str(std::string const &s) { return s.length() > 0 ? s.c_str() : nullptr; } Usage: mosqpp::tls_set(c_str(MqttOptions->CAFile), c_str(MqttOptions->CAPath), c_str(MqttOptions->CertFile), c_str(MqttOptions->KeyFile));

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.