问题描述
我在一个套接字接口中犯了一个错误,我写了一段时间,当我在代码中查找另一个问题时,我刚刚注意到了这个问题。套接字接收一个字符串,并将其传递给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,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;
}
上面的代码不会引起任何明显的问题,但是如果存在问题,我想纠正它。显然,字符数组正在转换为字符串,但是通过什么机制呢?我想我有四个问题:
- 此字符串是在堆栈上转换并通过引用传递还是通过值传递?
- 是否使用operator =重载? “从c字符串”构造器?其他机制?
- 基于2的效率不如使用构造函数显式转换为字符串的效率高?
- 这很危险吗? :)
使用g ++编译(Ubuntu 5.4.0-6ubuntu1〜16.04.12)5.4.0 20160609
解决方法
std::string
具有非显式构造函数(即未标记有explicit
关键字),该构造函数采用const char*
参数并复制字符,直到第一个{{ 1}}(如果字符串中不存在此类字符,则该行为是不确定的)。换句话说,它执行源数据的副本。 It's overload #5 on this page。
'\0'
隐式衰减到const char[]
,您可以将临时变量传递给具有const char*
引用参数的函数。顺便说一下,这仅在引用为const
时有效。如果您不能使用const
,请按值传递。
因此,当您向该函数传递const
时,将使用该构造函数构造一个const char[]
类型的临时对象,并将其绑定到该参数。临时将在函数调用期间保持活动状态,并在返回时销毁。
请记住所有这些,让我们解决您的问题:
- 它通过引用传递,但是引用是指向一个临时对象。
- 构造函数,因为我们正在构造一个对象。
std::string
还有一个std::string
带有一个operator=
参数,但这从未用于隐式转换:您需要显式地分配一些东西。 - 由于运行相同的代码,因此性能是相同的,但是由于复制了数据而不是引用数据,因此确实会产生一些开销。如果存在问题,请改用
const char*
。 - 这是安全的,只要您不尝试将对参数的引用或指针保留的时间长于函数调用的时间,因为此后该对象可能仍然不活动(但在使用引用参数时,请始终牢记这一点)。您还需要确保所传递的C字符串正确以null终止。
- 此字符串是否在堆栈上转换
该语言没有指定临时对象的存储,但是在这种情况下,它可能存储在堆栈中,是的。
还是按值传递?
该参数是一个引用。因此,您正在“通过引用传递”。
- 是否使用operator =重载?
不。您不在那里使用operator =,为什么呢?
“来自c字符串”的构造函数?
是的
- 基于2的效率不如使用构造函数显式转换为字符串的效率高?
不。隐式还是显式创建对象与效率无关。
创建std::string
的效率可能比不创建它的效率低,您可以通过不接受对字符串的引用作为参数来实现。您可以改用字符串视图。
- 这很危险吗?
不是特别。在某些情况下,当程序员不注意隐式转换时,可能会引起一些问题,但是通常,它们通过减少冗长性来简化语言。