【问题标题】:C++ pass string by reference vs pass char array by referenceC ++通过引用传递字符串与通过引用传递char数组
【发布时间】:2018-09-01 07:06:25
【问题描述】:

好的,所以我是 C++ 新手,我只是想问一下为什么您不应该通过引用“&”符号来传递 char 数组,但您应该使用字符串,因为这两个参数都是指针。我写的示例代码:

void changeChar(char* buffer, int bSize) {
    strcpy_s(buffer, bSize, "test123");
}

void changeString(string* buffer) {
    *buffer = "test321";
}

char mychar[10] = "hello world";
string mystr;

changeChar(mychar, sizeof(mychar));
changeString(&mystr);

【问题讨论】:

  • 请注意,您提供的示例中没有使用任何引用。
  • std::string 不是指针,它是一个类。通过值传递一个类会创建一个副本,而通过引用传递它允许您访问原始对象。通过引用传递指针与通过值传递相比没有净收益,而在std::string 的情况下,它避免了创建副本。
  • char mychar[10] = "hello world"; 你觉得在做什么?
  • 好的,但是我不是将指针“缓冲区”分配给 mystr 的内存地址还是发生了什么?
  • changeString(&mystr); 中的& 是地址运算符(与引用无关),它返回mystr 的地址见:en.cppreference.com/w/cpp/language/…

标签: c++ arrays pointers stdstring


【解决方案1】:

changeChar() 将char* 指针指向位于内存中某处 的char(该函数假定char* 实际上指向指定大小的char[] 数组) .

一个固定长度的数组衰减为一个指向它的第一个元素的指针,当它只被它的名字引用时。因此,当需要 char* 指针时,无需(也不能)使用 operator& 将您的 mychar[] 数组传递给您的 changeChar() 函数。

如果您不想通过指针传递mychar,则必须通过引用传递它(否则,通过值传递它会复制数组,然后函数将无法修改原始数组)。在这种情况下,编译器可以为您推断出数组大小:

template<size_t size>
void changeChar(char (&buffer)[size]) {
    strcpy_s(buffer, size, "test123");
}

char mychar[] = "hello world";
changeChar(mychar);

changeString() 将一个string* 指针指向位于内存中某处 的string 对象。

如果不使用operator&amp;(或std::addressof(),当类覆盖operator&amp;),则不能通过指针传递对象来获取对象的地址(除非它是用new分配的,这不是你的例子中的情况)。

如果您不想通过指针传递string 对象,则必须通过引用传递它(否则,通过值传递对象将复制该对象,并且该函数不会能够修改原始对象):

void changeString(string &buffer) {
    buffer = "test321";
}

string mystr;
changeString(mystr);

【讨论】:

  • 非常感谢我想我明白了!因此,当按名称引用时,数组通常会变成一个指针,或者它只是 char 数组还是我完全错了?
  • 任何类型的定长数组都会衰减为指针,它不仅仅针对char数组。
  • 好的,非常感谢。这让我明白了很多。
【解决方案2】:

您需要知道,std::string 不是内置类型。它是一个实现各种自定义行为的类,例如在对象复制时创建硬拷贝。

"some text" // this is a string literal, meaning the type is const char[num]

当您输入字符串文字时,它很可能位于名为“.rodata”(只读数据)的代码部分内。您不能合法地修改此字符的值。该文本还有一个“空终止符” - 最后的值为零的字符。它很有用,因为您需要知道文字何时结束。 num 总是 number of characters +1,因为空终止符。

当你写这个时:

const char* text = "hello world!";
// note that this is illegal:
// char* text = "hello world!"; // literal is read-only.

你只是说:

让text指向文字所在的内存。

复制文本实际上需要更多的工作。必须明确完成:

char* notReadOnly = new char[30]; // you can allocate some more
// program will still interpret character of value 0 as the end, even if buffer is bigger
std::strcpy(notReadOnly, "hello world");
// use string literal as src in std::strcpy

注意,你也需要手动删除它:

delete[] notReadOnly;

std::string 使它更容易。当你这样写时,它会自动复制文本:

std::string text = "some string literal";

std::string 的复制构造函数也会制作缓冲区的硬拷贝。即使std::string 类看起来像这样:

class string
{
    char *buffer;
    std::size_t numberOfCharacters;
};

每次复制时,都会对buffer进行硬拷贝,如下所示:

class string
{
    // rest
    string(const string &other)
    {
        numberOfCharacters = other.numberOfCharacters;
        buffer = new char[numberOfCharacters];
        // copy everything
        std::strncpy(buffer, other.buffer, numberOfCharacters);
    }
};

请注意,这只是一个简化的示例。

std::string a = "some text";
std::string b = a; // copy constructor is called. It uses method implemented above

const char* x = "some text2";
const char* y = x; // copy constructor is called. Only the address is copied, there is no hard copy of the actual buffer.

当您将变量作为参数传递给函数时,也会调用复制构造函数。但是在一些常见情况下,编译器可以对其进行优化。

【讨论】:

  • 对不起,我是新手,所以我不太明白......我的代码是否会额外复制“mystr”,或者字符串指针“buffer”是否直接指向“mystr”?
  • 当您复制指向 char 的指针时,您只复制内存地址。两个指针都指向同一个位置。
猜你喜欢
  • 1970-01-01
  • 2014-08-11
  • 2017-07-25
  • 2016-07-05
  • 1970-01-01
  • 1970-01-01
  • 2016-02-28
  • 1970-01-01
  • 2020-12-06
相关资源
最近更新 更多