如何将 std::string 作为构造函数参数传递,并将其保存的 C 字符串存储在 void 指针中?

How do I pass a std::string as a constructor argument and store the C string it holds in a void pointer?

本文关键字:字符串 存储 指针 保存 void string std 构造函数 参数传递      更新时间:2023-10-16

我有一个构造函数,它接受对std::string对象的const引用,并且应该将std::string的内部C字符串存储在void指针成员变量中。但是,当使用void指针时,我的程序会出现段错误,并且gdb说指针指向地址0x01。这是我的消息来源:

class Foo {
public:
Foo(const std::string& str);
void* getData();
private:
Foo(void* newData);
void* data;
};

福.cpp:

Foo::Foo(const std::string& str)
: Foo(str.c_str())
{
//nothing
}
void* Foo::getData() {
return data;
}
Foo::Foo(void* newData)
: data(newData)
{
//nothing
}

主.cpp:

int func(void* data);
int main() {
Foo f("bar");
func(f.getData()); //segfault here
return 0;
}
int func(void* data) {
std::string str = (char*)data;
std::cout << str << std::endl;
return 0;
}

调用f.getData()时,由"bar"构造的字符串不再存在,因此指向其内部字符数组的指针不再有效。该字符串只是为函数调用构造的,并在执行main-function 的其余部分之前再次析构。 取消引用无效指针时会发生段错误。

请尝试以下操作:

const std::string str("bar");
Foo f(str);

这样,当需要数据时,字符串仍在范围内。


除此之外,整体方法不可取。如果可能的话,最好不要使用void*指针和原始指针,或者至少在对象中安全地管理它们。您的问题已经清楚地说明了为什么这种指针使用不安全且容易出错。

Foo f("bar"(;

您正在将对临时值的引用传递给构造函数。对象的生存期仅在构造函数内。因此,空白*数据指向已删除的内存。

更准确地说,如果您不知道,您可能想知道l值和r 值在C++中的区别。

例如(int a = 5

这里a是 l 值,5是 r 值。简单地说,它们是数据类型的值类别

https://en.cppreference.com/w/cpp/language/value_category

切勿存储对 r 值的引用。在执行任何操作之前,请始终检查对象的生存期,并确保对象在操作完成之前保持活动状态。

溶液

string a = "bar";
Foo foo(a);

这里 a 是 l 值。但用户有责任确保a 的生命范围不仅仅是foo

或更好

string a = "bar";
{
Foo foo(a);
}

通过这种方式,您可以确保

代码崩溃和烧毁的原因是

: Foo(str.c_str())

正在呼叫

Foo(const std::string& str);

而不是

Foo(void* newData);

所以你有无限递归。这一切都很糟糕,我建议您重新考虑您的方法,但是只是为了让它运行,请明确void *str.c_str()

: Foo((void *)str.c_str())

当然,将"bar"作为一个独立的string以避免处理临时变量,并将字符串传递给构造函数。这样,指针将一直有效,直到包含string的范围结束。

演示:https://ideone.com/v7YfBX

首先,我建议不要使用 void* 在极少数情况下,需要使用 void*,并且会丢失任何有用的类型信息。

如果要直接在 std::string 对象中操作位,则从 C++ 17 开始,字符串上的 data 方法可以直接访问字符,而不是常量。

如果你想让你的代码更安全,只需将std::string存储为Foo类的成员变量,并使用你可用的方法。 这也意味着您无需手动跟踪从c_str或数据方法调用传递的字符串的内部指针。

例如(部分示例(

class Foo {
public:
Foo(const std::string& str);
const char* getData() const;
char* getData();
private:
std::string m_str;
};
Foo::Foo(const std::string& str)
: m_str(str)
{
}
const char* Foo::getData() const
{
return m_str.c_str();
}
char* Foo::getData()
{
// Note: Need C++ 17
return m_str.data();
}