将 char 数组传递给需要 const std::string 引用的函数

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

我在不久前写的套接字接口中犯了一个错误,我只是在查看代码以查找其他问题时才注意到这个问题。 socket接收到一串字符,传递给jsoncpp完成json解析。我可以几乎 理解这里发生的事情,但我无法理解它。我想了解引擎盖下实际发生的事情。这是最小的例子:

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

上面的代码没有引起任何明显的问题,但如果有问题我想更正它。显然字符数组正在转换为字符串,但通过什么机制呢?我想我有四个问题:

  1. 此字符串是在堆栈上转换并通过引用传递还是通过值传递?
  2. 是否使用 operator= 重载?一个“来自 c 字符串”的构造函数?其他一些机制?
  3. 基于 2,这是否比使用构造函数显式转换为字符串效率低?
  4. 这危险吗。 :)

用 g++ 编译 (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609

std::string 有一个 非显式 构造函数(即未标记 explicit 关键字),它采用 const char* 参数并复制字符直到第一个 '[=13=]' (如果字符串中不存在这样的字符,则行为未定义)。换句话说,它执行源数据的副本。 It's overload #5 on this page.

const char[] 隐式衰减为 const char*,您可以将临时值传递给采用 const 引用参数的函数。顺便说一下,这仅在引用为 const 时有效;如果你不能使用const,按值传递它。

因此,当您将 const char[] 传递给该函数时,将使用该构造函数构造一个 std::string 类型的临时对象,并绑定到参数。临时文件将在函数调用期间保持活动状态,并在 returns.

时被销毁

考虑到所有这些,让我们来解决您的问题:

  1. 它是通过引用传递的,但引用是对临时对象的引用。
  2. 一个构造函数,因为我们正在构造一个对象。 std::string 也有一个 operator= 接受一个 const char* 参数,但它从未用于隐式转换:你需要显式分配一些东西。
  3. 由于运行相同的代码,性能是相同的,但是您确实会产生一些开销,因为数据是复制的而不是引用的。如果这是一个问题,请改用 std::string_view
  4. 只要您不尝试保留对参数的引用或指针的时间超过函数调用,这是安全的,因为该对象之后可能不存在(但是您应该始终牢记这一点参考参数)。您还需要确保您传递的 C 字符串正确地以 null 结尾。
  1. Is this string converted on the stack

该语言没有指定临时对象的存储方式,但在这种情况下它可能存储在堆栈中,是的。

or is it passed by value?

参数为参考。因此,您是“通过引用传递”。

  1. Is it using the operator= overload?

没有。您没有在此处使用 operator=,那为什么要使用它?

A "from c-string" constructor?

是的。

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

没有。对象是隐式创建还是显式创建与效率无关。

然而,创建 std::string 可能比不创建它效率低,您可以通过不接受对字符串的引用作为参数来实现。您可以改用字符串视图。

  1. Is this dangerous.

不特别。在某些情况下,当程序员没有注意到隐式转换时,隐式转换可能会导致一些问题,但通常它们会通过减少冗长来简化语言。