为什么这是段错误?
Why is this segfaulting?
我有以下构建器构建 Tokens
:
// token_builder.h
class TokenBuilder
{
Keyword m_keyword;
TokenType m_type;
std::string m_symbol;
public:
TokenBuilder& set_keyword(Keyword);
TokenBuilder& set_toktype(TokenType);
TokenBuilder& set_symbol(std::string);
std::unique_ptr<Token>&& build();
};
// token_builder.cpp
TokenBuilder& TokenBuilder::set_keyword(Keyword k)
{
m_keyword = k;
return *this;
}
TokenBuilder& TokenBuilder::set_toktype(TokenType t)
{
m_type = t;
return *this;
}
TokenBuilder& TokenBuilder::set_symbol(std::string sym)
{
m_symbol = sym; // This is the point where it segfaults
return *this;
}
std::unique_ptr<Token>&& TokenBuilder::build()
{
std::unique_ptr<Token> token;
token->m_keyword = m_keyword;
token->m_type = m_type;
token->m_symbol = m_symbol;
return std::move(token);
}
在我尝试通过调用 TokenBuilder::set_symbol
初始化 m_symbol
时,程序以 SIGSEGV
停止。这是 main
的样子:
int main()
{
auto token = Token::builder()
.set_keyword(Keyword::IF)
.set_toktype(TokenType::ID)
.set_symbol("if")
.build();
std::cout << token->get_symbol() << std::endl;
}
如您所见,调用 set_keyword
和 set_toktype
不会导致任何错误。但是将文字 "if"(或 std::string
对象)传递给 set_symbol
会导致程序崩溃。按价值传递是有意的。进入 set_symbol
并分析 TokenBuilder
的状态并没有透露任何信息。正如预期的那样,m_keyword
设置为 Keyword::IF
,m_type
设置为 TokenType::ID
。这是崩溃的行:m_symbol = sym
.
上面的程序可能还有其他重要的问题(我使用 std::move
是否正确?很长一段时间后回到 C++),但这种感觉像是菜鸟会犯的愚蠢错误。我在 Windows 10(64 位)上使用 MinGW-w64 编译器。
这里是方便复制粘贴到你的机器的完整代码:
// src/include/token_builder.h
#ifndef TOKEN_BUILDER_H
#define TOKEN_BUILDER_H
#include <memory>
#include "token.h"
namespace funk
{
class Token;
class TokenBuilder
{
Keyword m_keyword;
TokenType m_type;
std::string m_symbol;
public:
TokenBuilder& set_keyword(Keyword);
TokenBuilder& set_toktype(TokenType);
TokenBuilder& set_symbol(std::string);
std::unique_ptr<Token>&& build();
};
}
#endif
// src/token_builder.cpp
#include "include/token.h"
#include "include/token_builder.h"
namespace funk
{
TokenBuilder& TokenBuilder::set_keyword(Keyword k)
{
m_keyword = k;
return *this;
}
TokenBuilder& TokenBuilder::set_toktype(TokenType t)
{
m_type = t;
return *this;
}
TokenBuilder& TokenBuilder::set_symbol(std::string sym)
{
m_symbol = sym;
return *this;
}
std::unique_ptr<Token>&& TokenBuilder::build()
{
std::unique_ptr<Token> token;
token->m_is_keyword = m_keyword != Keyword::_NONE_;
token->m_keyword = m_keyword;
token->m_type = m_type;
token->m_symbol = m_symbol;
return std::move(token);
}
}
// src/include/token.h
#ifndef TOKEN_H
#define TOKEN_H
#include <memory>
#include "keyword.h"
#include "token_type.h"
#include "token_builder.h"
namespace funk
{
class TokenBuilder;
class Token
{
friend class TokenBuilder;
Keyword m_keyword;
bool m_is_keyword;
std::string m_symbol;
TokenType m_type;
Token();
public:
Keyword& get_keyword ();
bool is_keyword();
std::string& get_symbol();
TokenType& get_type();
static TokenBuilder&& builder();
};
}
#endif // END TOKEN_H
// src/token.cpp
#include <string>
#include <memory>
#include "include/keyword.h"
#include "include/token_builder.h"
#include "include/token_type.h"
namespace funk
{
Keyword& Token::get_keyword()
{
return m_keyword;
}
bool Token::is_keyword()
{
return m_is_keyword;
}
std::string& Token::get_symbol()
{
return m_symbol;
}
TokenType& Token::get_type()
{
return m_type;
}
TokenBuilder&& Token::builder()
{
TokenBuilder builder;
return std::move(builder);
}
}
// src/main.cpp
#include <iostream>
#include "include/buffered_reader.h"
#include "include/token.h"
#include "include/token_builder.h"
int main()
{
using namespace funk;
auto token = Token::builder()
.set_keyword(Keyword::IF)
.set_toktype(TokenType::ID)
.set_symbol("if")
.build();
std::cout << token->get_symbol() << std::endl;
}
注意: 我尽我所能在 Whosebug 上查找了类似的问题,但没有找到符合我的情况的问题。如果您认为它与您之前遇到的问题相似,请随时标记重复并将 post 标记为 link 原始问题。谢谢!
std::unique_ptr<Token>&& TokenBuilder::build()
{
std::unique_ptr<Token> token;
// ...
return std::move(token);
}
您return引用了一个局部变量。在函数结束时,局部变量被销毁,returned 引用将保留指向其生命周期之外的对象。当您稍后尝试通过悬挂引用访问不存在的对象时,程序的行为是未定义的。
我有以下构建器构建 Tokens
:
// token_builder.h
class TokenBuilder
{
Keyword m_keyword;
TokenType m_type;
std::string m_symbol;
public:
TokenBuilder& set_keyword(Keyword);
TokenBuilder& set_toktype(TokenType);
TokenBuilder& set_symbol(std::string);
std::unique_ptr<Token>&& build();
};
// token_builder.cpp
TokenBuilder& TokenBuilder::set_keyword(Keyword k)
{
m_keyword = k;
return *this;
}
TokenBuilder& TokenBuilder::set_toktype(TokenType t)
{
m_type = t;
return *this;
}
TokenBuilder& TokenBuilder::set_symbol(std::string sym)
{
m_symbol = sym; // This is the point where it segfaults
return *this;
}
std::unique_ptr<Token>&& TokenBuilder::build()
{
std::unique_ptr<Token> token;
token->m_keyword = m_keyword;
token->m_type = m_type;
token->m_symbol = m_symbol;
return std::move(token);
}
在我尝试通过调用 TokenBuilder::set_symbol
初始化 m_symbol
时,程序以 SIGSEGV
停止。这是 main
的样子:
int main()
{
auto token = Token::builder()
.set_keyword(Keyword::IF)
.set_toktype(TokenType::ID)
.set_symbol("if")
.build();
std::cout << token->get_symbol() << std::endl;
}
如您所见,调用 set_keyword
和 set_toktype
不会导致任何错误。但是将文字 "if"(或 std::string
对象)传递给 set_symbol
会导致程序崩溃。按价值传递是有意的。进入 set_symbol
并分析 TokenBuilder
的状态并没有透露任何信息。正如预期的那样,m_keyword
设置为 Keyword::IF
,m_type
设置为 TokenType::ID
。这是崩溃的行:m_symbol = sym
.
上面的程序可能还有其他重要的问题(我使用 std::move
是否正确?很长一段时间后回到 C++),但这种感觉像是菜鸟会犯的愚蠢错误。我在 Windows 10(64 位)上使用 MinGW-w64 编译器。
这里是方便复制粘贴到你的机器的完整代码:
// src/include/token_builder.h
#ifndef TOKEN_BUILDER_H
#define TOKEN_BUILDER_H
#include <memory>
#include "token.h"
namespace funk
{
class Token;
class TokenBuilder
{
Keyword m_keyword;
TokenType m_type;
std::string m_symbol;
public:
TokenBuilder& set_keyword(Keyword);
TokenBuilder& set_toktype(TokenType);
TokenBuilder& set_symbol(std::string);
std::unique_ptr<Token>&& build();
};
}
#endif
// src/token_builder.cpp
#include "include/token.h"
#include "include/token_builder.h"
namespace funk
{
TokenBuilder& TokenBuilder::set_keyword(Keyword k)
{
m_keyword = k;
return *this;
}
TokenBuilder& TokenBuilder::set_toktype(TokenType t)
{
m_type = t;
return *this;
}
TokenBuilder& TokenBuilder::set_symbol(std::string sym)
{
m_symbol = sym;
return *this;
}
std::unique_ptr<Token>&& TokenBuilder::build()
{
std::unique_ptr<Token> token;
token->m_is_keyword = m_keyword != Keyword::_NONE_;
token->m_keyword = m_keyword;
token->m_type = m_type;
token->m_symbol = m_symbol;
return std::move(token);
}
}
// src/include/token.h
#ifndef TOKEN_H
#define TOKEN_H
#include <memory>
#include "keyword.h"
#include "token_type.h"
#include "token_builder.h"
namespace funk
{
class TokenBuilder;
class Token
{
friend class TokenBuilder;
Keyword m_keyword;
bool m_is_keyword;
std::string m_symbol;
TokenType m_type;
Token();
public:
Keyword& get_keyword ();
bool is_keyword();
std::string& get_symbol();
TokenType& get_type();
static TokenBuilder&& builder();
};
}
#endif // END TOKEN_H
// src/token.cpp
#include <string>
#include <memory>
#include "include/keyword.h"
#include "include/token_builder.h"
#include "include/token_type.h"
namespace funk
{
Keyword& Token::get_keyword()
{
return m_keyword;
}
bool Token::is_keyword()
{
return m_is_keyword;
}
std::string& Token::get_symbol()
{
return m_symbol;
}
TokenType& Token::get_type()
{
return m_type;
}
TokenBuilder&& Token::builder()
{
TokenBuilder builder;
return std::move(builder);
}
}
// src/main.cpp
#include <iostream>
#include "include/buffered_reader.h"
#include "include/token.h"
#include "include/token_builder.h"
int main()
{
using namespace funk;
auto token = Token::builder()
.set_keyword(Keyword::IF)
.set_toktype(TokenType::ID)
.set_symbol("if")
.build();
std::cout << token->get_symbol() << std::endl;
}
注意: 我尽我所能在 Whosebug 上查找了类似的问题,但没有找到符合我的情况的问题。如果您认为它与您之前遇到的问题相似,请随时标记重复并将 post 标记为 link 原始问题。谢谢!
std::unique_ptr<Token>&& TokenBuilder::build() { std::unique_ptr<Token> token; // ... return std::move(token); }
您return引用了一个局部变量。在函数结束时,局部变量被销毁,returned 引用将保留指向其生命周期之外的对象。当您稍后尝试通过悬挂引用访问不存在的对象时,程序的行为是未定义的。