将指针临时绑定到引用

时间:2010-04-01 13:58:51

标签: c++

请参阅以下代码。在此代码中,我将const char*返回的test.c_str()存储到引用中。我的问题是 - data是否正确引用test的内容?我认为test.c_str()返回的ptr将是一个临时的,如果我将它绑定到引用,那么引用将无效。

我的想法是否正确?

class RefPtrTest
{
    std::string test;
    StoringClass storingClass;
public: 
    RefPtrTest(): test("hello"), storingClass(test.c_str())
    {
    }
}

其中StoringClass是

class StoringClass 
{
    const char*& data;
public: 
    StoringClass (const char*& input): data(input)
    {
    }
}

EDIT1: 我们不要考虑std :: string正在做什么。假设我使用自己的名为mystring的类

class RefPtrTest
{
    const mystring test;
    StoringClass storingClass;
public: 
    RefPtrTest(): test("hello"), storingClass(test.getInternalPointer())
    {
    }
}

getInternalPointer直接返回内部指针。我想验证这个假设,storingClass(test.getInternalPointer())test.getInternalPointer()返回的ptr将是临时的,如果我将它绑定到引用将无效的引用。我的想法是否正确?

EDIT2: StoringClass不受我的控制。基本上它是一个模板类,它存储对类型的引用。我将它用于const char*。我知道你提出的所有设计问题。但是我不能改变那个类,我必须将它用于const char *。除此之外别无他法。

6 个答案:

答案 0 :(得分:3)

是的,你的想法是正确的(test.c_str()返回一个temp,所以你不能用它来初始化一个引用),除非test.c_str()实际上返回一个指针的引用,我不知道我认为它确实......是吗?

这应该会给你一个编译错误,但是,你试过吗?

在这种特殊情况下,实际使用指针进行某些操作并没有多大意义。但是如果你只是询问对指针的引用,那么你是正确的(无论类型如何)。

答案 1 :(得分:3)

该标准对c_str(21.3.6 / 2)

有以下说法
  

要求:程序不得更改   存储在数组中的任何值。   程序也不应该对待   返回值作为有效指针   任何后续调用a后的值   类的非const成员函数   basic_string指定相同的   这是对象。

所以答案是否定的,你不能将指针视为对字符串内容的引用(在任何非const函数调用字符串之后)。

答案 2 :(得分:1)

如果您正在尝试这样做,则不应直接修改字符串缓冲区。

当您处理指针时,如果要更改指针类型所包含的地址,则只需要对指针的引用。如果您只想更改缓冲区,则只需存储char *。

如果你想访问这样的缓冲区,请使用std :: vector,而不是这样:

std::vector<char> v;
v.resize(size);
strcpy(&v.front(), "testing");

答案 3 :(得分:1)

请参阅以下有关cplusplus.com中std :: string c_str()成员函数的注释:

  

返回的数组指向一个内部位置,该位置具有此字符序列所需的存储空间加上其终止的空字符,但此数组中的值不应在程序中修改,只能保持不变,直到接下来调用字符串对象的非常量成员函数。

虽然您没有在发布的代码中调用任何非const成员函数,但这不是一个好主意。在RefPtrTest类中修改私有std :: sting测试变量时,会无意中影响StoringClass类(这违反了RefPtrTest的封装)。有些人以后维护你的代码(也许你)可能没有意识到这一点,并引入了一个错误/崩溃。

答案 4 :(得分:1)

如果StoringClass需要对指针的引用,那么你必须确保有一个指针供它引用(并修改,因为它不是一个const引用),其生命周期与引用的生命周期一样长。 :

#include <string>
#include <iostream>

template <typename T>
class StoringClass {
    T& data;
public: 
    StoringClass (T& input): data(input) { }
    void print() const { std::cout << data << "\n"; }
    void set(T x) { data = x; }
};

class RefPtrTest {
    const std::string test;
    const char *ptr;
    StoringClass<const char*> storingClass;
public: 
    RefPtrTest(): test("hello"), ptr(test.c_str()), storingClass(ptr) { }
    void print() const { storingClass.print(); }
    void set(const char* x) { storingClass.set(x); }
};

int main() {
    RefPtrTest t;
    t.print();
    t.set("world");
    t.print();
}

输出:

hello
world

IMO StoringClass有点奇怪。例如,我也可以标记set函数const,它仍然有效。但是如果你必须使用它,你必须使用它。如果您可以使用StoringClass<const char *const>,那可能会更好:它将确保您不会调用任何修改指针的StoringClass函数。你问这个问题的方式表明你不希望这种情况发生。

编辑:

如果test不是const,那么RefPtrTest可以有一个函数:

void set_another_way(const char *x) { test = x; set(test.c_str()); }

哪个会修改字符串并更新指向storingClass的指针。函数体等同于test = x; ptr = test.c_str();。假设单线程代码也解决了test.c_str()返回的指针值有效性的任何问题,前提是set_another_waytest被修改的唯一方法。

坦率地说,StoringClass不应该被称为StoringClass。它不存储任何东西;-p

答案 5 :(得分:-1)

可能有效。但是,您不应该依赖此行为。

string类实现下面有char*c_str()方法可能只返回指向该数组开头的指针。但是,随着字符串随时间的变化,此内部数组可能会在内存中移动,无论如何都会调整大小。每次您要将c_str()转换为string时,都应调用char*

它可能只返回指向内部存储器的指针,所以无论如何都非常快。