我有一个班级说,
class Foo
{
public:
void ProcessString(std::string &buffer)
{
// perform operations on std::string
// call other functions within class
// which use same std::string string
}
void Bar(std::string &buffer)
{
// perform other operations on "std::string" buffer
}
void Baz(std::string &buffer)
{
// perform other operations on "std::string" buffer
}
};
此类尝试使用std::string
缓冲区在这些条件下使用各种方法对其执行操作:
std::string
副本。例如:
// Once an object is created
Foo myObject;
// We could pass many different std::string's to same method without copying
std::string s1, s2, s3;
myObject.ProcessString(s1);
myObject.ProcessString(s2);
myObject.ProcessString(s3);
我可以使用该字符串并将其指定为类成员,以便其他使用的函数可以了解它。
但似乎我们不能拥有引用类成员std::string &buffer
,因为它只能从构造函数初始化。
我可以使用指向std::string
的指针,即std::string *buffer
,并将其用作类成员,然后传递s1, s2, s3
的地址。
class Foo
{
public:
void ProcessString(std::string *buf)
{
// Save pointer
buffer = buf;
// perform operations on std::string
// call other functions within class
// which use same std::string string
}
void Bar()
{
// perform other operations on "std::string" buffer
}
void Baz()
{
// perform other operations on "std::string" buffer
}
private:
std::string *buffer;
};
或者,另一种方式是将每个函数传递给std::string
缓冲区,就像上面第一个例子中显示的一样。
两种方式似乎都有点丑陋的变通方法能够使用std::string
而无需复制,因为我很少看到使用std :: string作为指针或传递类的所有函数相同的参数
这周围有更好的或我正在做的事情还不错吗?
答案 0 :(得分:7)
在MyObject中保留一个引用或指向不受对象拥有的字符串的指针是危险的。很容易得到 讨厌的未定义行为 。
请看以下法律示例(Bar是公开的):
myObject.ProcessString(s1); // start with s1 and keep its address
myObject.Bar(); // works with s1 (using address previously stored)
请看以下UB:
if (is_today) {
myObject.ProcessString(string("Hello")); // uses an automatic temporary string
} // !! end of block: temporary is destroyed!
else {
string tmp = to_string(1234); // create a block variable
myObject.ProcessString(tmp); // call the main function
} // !! end of block: tmp is destroyed
myObject.Bar(); // expects to work with pointer, but in reality use an object that was already destroyed !! => UB
错误是非常讨厌的,因为在阅读功能的使用时,一切似乎都很好并且管理得很好。通过自动销毁bloc变量隐藏了这个问题。
因此,如果你真的想避免使用字符串的副本,你可以按照设想使用指针,但是你只能在ProcessString()直接调用的函数中使用这个指针,并使这些函数成为私有的。
在所有其他情况下,我强烈建议重新考虑您的立场,并设想:
string&
个参数。这样可以避免副本,但会给调用者留下组织正确管理字符串的责任。 答案 1 :(得分:6)
你基本上需要回答这个问题:谁拥有字符串? Foo
拥有字符串吗?外部呼叫者是否拥有该字符串?或者他们都共享字符串的所有权。
“拥有”字符串意味着字符串的生命周期与它相关联。因此,如果Foo拥有该字符串,则当Foo停止存在或销毁它时,该字符串将停止存在。共享所有权要复杂得多,但我们可以通过说只要有任何所有者保留字符串就可以使其更简单。
每种情况都有不同的答案:
Foo
拥有字符串:将字符串复制到Foo
,然后让成员方法改变它。Foo
永远不应该在其自己的堆栈之外保存对字符串的引用,因为字符串可能在不知情的情况下被销毁。这意味着它需要通过引用传递给每个使用它的方法,并且不拥有它,即使这些方法属于同一个类。shared_ptr
,然后将该shared_ptr传递给共享所有权的每个实例。然后,将shared_ptr复制到成员变量,然后方法访问它。这比通过引用传递的开销高得多,但是如果你想要共享所有权,那么这是最安全的方法之一。实际上还有其他几种方法来模拟所有权,但它们往往更为深奥。所有权薄弱,可转让所有权等。
答案 2 :(得分:0)
因为您的要求是
1.我不想传递我已经拥有的std :: string的副本。
2.我不想创建这个类的多个对象。
使用pass by ref将是1的解决方案 使用static将是2的解决方案。因为它是一个静态的memeber方法,所以只有这个方法的一个副本。但它不属于任何物体。话虽如此,您可以直接调用此方法,而不是通过对象。
例如,
class Foo
{
static void ProcessString(std::string &s)
{
// perform operations on std::string
// call other functions within class
// which use same std::string string
}
}
当你调用这个方法时,它会是这样的:
std::string s1, s2, s3;
Foo::ProcessString(s1);
Foo::ProcessString(s2);
Foo::ProcessString(s3);
更进一步,如果你只想要这个类的一个实例,你可以参考单例设计模式。