2010-04-01 49 views
4

请参阅下面的代码。在这段代码中,我将test.c_str()返回的const char*存储为参考。我的问题是 - 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直接返回内部指针。我想验证这个假设,而由test.getInternalPointer()返回的storingClass(test.getInternalPointer()) ptr将是一个临时的,如果我将它绑定到引用将无效的引用。我的想法是否正确?

EDIT2: StoringClass不在我的控制之下。基本上它是一个模板类,它存储对类型的引用。我使用它为const char*。我知道你提出的所有设计问题。但是我不能改变这个班级,所以我必须用它来做const char *。没有别的办法。

+0

我不明白为什么要存储对指针的引用而不是指针的副本。 – pmr 2010-04-01 14:11:05

回答

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是有点怪。举例来说,我也可以标记函数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

+0

的内容我已经完全做了同样的事情(接受另一个'const char *')来解决这个问题,因为这给了我RAII语义。 – 2010-04-02 13:43:08

3

是的,你的想法是正确的(test.c_str()返回一个临时值,所以你不能用它来初始化一个引用),除非test.c_str()实际上返回一个指针的引用,我不认为它的确如此。可以?

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

在这种特殊情况下,实际上使用指针来表示某些东西没有多大意义。但是,如果你只是询问指针的引用,那么你是正确的(不管类型)。

+1

test.c_str()返回一个指针,test是一个'std :: string' – 2010-04-01 14:03:17

+0

我只是不确定std :: string :: c_str()是否返回指针的引用。 – falstro 2010-04-01 14:04:48

+0

@roe'const'对临时对象的引用是合法的,参见以下内容:http://herbsutter.spaces.live.com/blog/cns!2D4327CC297151BB!378.entry(尽管在这种特殊情况下使用引用是毫无意义的)。 – 2010-04-01 14:25:23

3

标准具有以下说关于c_str(21.3.6/2)

要求:该方案不得改变 任何数组中存储的值的。 也不得程序到类 basic_string的,指定相同 对象作为这个的 非const构件功能的任何后续调用后处理 返回值作为一个有效指针值 。

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

+0

好吧,这很好,我没有调用任何非const成员函数。我不想改变它。我正在使用它,这是因为我正在使用需要const char *的StoringClass,并且我只构造了一次这个字符串 – 2010-04-01 14:06:53

+0

@Yogesh Arora您应该将const char *&data改为const char *数据 – 2010-04-01 14:11:12

+1

@Yogesh:如果你想要做的只是有效的,你首先需要什么参考? – UncleBens 2010-04-01 14:12:20

-1

它可能是有效的。然而,你不应该依赖这种行为。

string类的实现有一个char*下方和c_str()方法可能只是返回指向该数组的开始的指针。然而,随着时间的推移字符串发生变化,这个内部数组可能会被移动到内存中,无论如何调整大小。每当您想将string转换为char*时,您应该调用c_str()

它可能只是返回指向内部存储器的指针,所以反正非常快。

+1

我在这里看不到相关性,他在谈论对指针的引用,不是吗?不是该指针是否有意义。 – falstro 2010-04-01 14:06:30

+0

@roe'我的问题是数据是否会正确引用测试' – pajton 2010-04-01 14:33:17

1

如果这是你正在做的事,你不应该直接修改字符串缓冲区。

当你在处理指针时,如果你想改变指针类型的地址,你只需要一个指针的引用。如果你只想改变缓冲区,那么你可以简单地存储一个char *。

如果您要访问的缓冲区像这样使用std ::向量与替代是这样的:

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

见有关的std :: string c_str()成员函数以下评论来自cplusplus.com

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

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