简体   繁体   中英

Passing a char array to a function that expects a const std::string reference

I made a mistake in a socket interface I wrote a while back and I just noticed the problem while looking through the code for a different issue. The socket receives a string of characters and passes it to jsoncpp to complete the json parsing. I can almost understand what is happening here but I can't get my head around it. I would like to grasp what is actually happening under the hood. Here is the minimum example:

#include <iostream>
#include <cstring>

void doSomethingWithAString(const std::string &val) {
    std::cout << val.size() << std::endl;
    std::cout << val << std::endl;
}

int main()
{
    char responseBufferForSocket[10000];
    memset(responseBufferForSocket, 0, 10000);

    //Lets simulate a response from a socket connection
    responseBufferForSocket[0] = 'H';
    responseBufferForSocket[1] = 'i';
    responseBufferForSocket[2] = '?';

    // Now lets pass a .... the address of the first char in the array...
    // wait a minute..that's not a const std::string& ... but hey, it's ok it *works*!
    doSomethingWithAString(responseBufferForSocket);

    return 0;
}

The code above is not causing any obvious issues but I would like to correct it if there is a problem lurking. Obviously the character array is being transformed to a string, but by what mechanism? I guess I have four questions:

  1. Is this string converted on the stack and passed by reference or is it passed by value?
  2. Is it using the operator= overload? A "from c-string" constructor? Some other mechanism?
  3. Based on 2 is this less efficient in than converting to a string explicitly using a constructor?
  4. Is this dangerous. :)

compiled with g++ (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609

std::string has a non explicit constructor (ie not marked with the explicit keyword) that takes a const char* parameter and copies characters until the first '\0' (the behaviour is undefined if no such character exists in the string). In other words, it performs a copy of the source data. It's overload #5 on this page .

const char[] implicitly decays to const char* , and you can pass a temporary to a function taking a const reference parameter. This only works if the reference is const , by the way; if you can't use const , pass it by value.

And so, when you pass a const char[] to that function, a temporary object of type std::string is constructed using that constructor, and bound to the parameter. The temporary will remain alive for the duration of the function call, and will be destroyed when it returns.

With all that in mind, let's address your questions:

  1. It's passed by reference, but the reference is to a temporary object.
  2. A constructor, since we're constructing an object. std::string also has an operator= taking a const char* parameter, but that's never used for implicit conversions: you'll need to be explicitly assigning something.
  3. The performance is the same since the same code runs, but you do incur some overhead because the data is copied instead of referenced. If that is an issue, use std::string_view instead.
  4. It's safe as long as you don't try to keep a reference or pointer to the parameter for longer than the function call, because the object might not be alive afterwards (but then you should always keep that in mind with reference parameters). You also need to make sure that the C string you're passing is properly null terminated.
  1. Is this string converted on the stack

The language doesn't specify the storage of temporary objects, but in this case it is probably stored on the stack, yes.

or is it passed by value?

The argument is a reference. Therefore you are "passing by reference".

  1. Is it using the operator= overload?

No. You aren't using operator= there, so why would it?

A "from c-string" constructor?

Yes.

  1. Based on 2 is this less efficient in than converting to a string explicitly using a constructor?

No. Whether object is created implicitly or explicitly is irrelevant to efficiency.

Creating a std::string is however potentially less efficient than not creating it which you could achieve by not accepting a reference to a string as the argument. You could use a string view instead.

  1. Is this dangerous.

Not particularly. In some cases implicit conversions can cause a bit of problems when the programmers doesn't notice them, but typically they simplify the language by reducing verbosity.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM