如何解决使用C ++ Lambda表达式初始化类成员
我想使用lambda表达式初始化一个类成员(std::string filePath
)。
程序可以正常编译,但是没有输出。怎么了?
#include <iostream>
#include <string>
class MyString
{
public:
std::string filePath = [this] ()
{
return onestr.append(" two");
}();
std::string onestr;
};
int main()
{
MyString str;
str.onestr = std::string(" one");
printf("%s",str.onestr.c_str());
}
解决方法
我在Linux 5.8.6上使用clang v10.0.1编译了您的代码。您的代码进入了核心转储。以下是valgrind
的一些日志(为了避免混淆而进行了简化):
==12170== Conditional jump or move depends on uninitialised value(s)
==12170== at 0x49BEAFE: _M_check_length (basic_string.h:322)
==12170== by 0x49BEAFE: std::string::append(char const*) (basic_string.h:1238)
==12170== by 0x10944A: MyString::filePath::{lambda()#1}::operator()[abi:cxx11]() const (test.cc:9)
==12170== by 0x109390: MyString::MyString() (test.cc:7)
==12170== by 0x109270: main (test.cc:17)
显然,函数append
出问题了。实际上,您的问题是您在初始化之前使用oneStr
。
根据cppreference:
https://en.cppreference.com/w/cpp/language/constructor
列表中成员初始化程序的顺序无关紧要:实际的初始化顺序如下:
...
3)然后,按类定义中的声明顺序初始化非静态数据成员。
因此,filePath
在oneStr
被初始化之前被初始化。计算lambda,捕获this
,this->oneStr
未初始化。
更改声明顺序将解决此未定义行为:
#include <iostream>
#include <string>
class MyString
{
public:
std::string oneStr;
std::string filePath = [this] ()
{
return oneStr.append(" two");
}();
};
int main()
{
MyString str;
str.oneStr = std::string(" one");
printf("%s",str.oneStr.c_str());
}
但是仍然可能无法获得预期的结果(也许 one two
?)。您只会看到 one
打印。这是因为oneStr首先用""
初始化,然后在" two"
中附加了MyString::MyString()
;但最终在使用" one"
函数进行打印之前已分配了main
。
已更新。
#include <iostream>
#include <string>
struct MyString{
std::string filePath = [this] () {
return oneStr.append(" two");
}();
std::string oneStr;
};
int main(){
MyString str; // 1
str.oneStr = std::string(" one"); // 2
std::cout << str.oneStr << '\n'; // 3
}
在“ 1”行str
对象已创建。
filePath
字符串首先被初始化。 Lambda捕获this
,但是oneStr
尚未初始化,因为它被定义为第二个成员。
Lambda正在使用oneStr
,因此没人知道结果是什么。实际上,程序会以静默方式崩溃。
如果您希望示例打印“一二”,请构造一个构造函数并在那里初始化oneStr
。
这是工作示例:
#include <iostream>
#include <string>
struct MyString{
MyString(std::string oneStr) : oneStr(std::move(oneStr)){}
std::string oneStr;
std::string filePath = [this] () {
return oneStr.append(" two");
}();
};
int main(){
MyString str(" one");
std::cout << str.oneStr << '\n';
}
https://gcc.godbolt.org/z/93xbcr
,我不确定您使用的是哪个编译器,但是g ++中的代码会给出分段错误,因为当调用lambda时oneStr不存在。如果您颠倒了顺序,它应该可以工作,但是请注意,str.oneStr = std :: string(“ one”)行将用“ 1”替换“ 2”。也许您想要str.oneStr = str.oneStr + std :: string(“ one”)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。