You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

删除const指针(非指向const的指针)是否合法?代码崩溃分析

成员声明为Lexer* const lexer_时触发段错误的问题分析

排查代码段错误时发现:将类成员声明为Lexer* const lexer_会导致程序崩溃,去掉const修饰后程序运行正常,特此询问该位置是否允许使用const。

编辑记录

  • Edit1:代码已遵循“rule of five”规则,问题仍存在。
  • Edit2:仅向printf的%p格式符传递void*类型参数,问题仍存在。
  • Edit3:经确认,这是一个GCC编译器Bug。

编译环境与命令

测试环境为Linux x86_64平台,使用g++ v11.3编译,编译命令如下:

g++ main.cpp -o main.x -fsanitize=address -Werror=all -Werror=extra

错误输出(带const修饰时)

运行程序触发AddressSanitizer的堆使用后释放错误,输出如下:

0x602000000010 = new Lexer
0x602000000030 = new Token
0x7ffca90b51f0 = new Expression
0x7ffca90b51f0 = start delete Expression
0x602000000010 = start delete Lexer
0x602000000030 = delete Token
0x602000000010 = done delete Lexer
=================================================================
==1232849==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000030 at pc 0x556fc889953d bp 0x7ffca90b5190 sp 0x7ffca90b5180
READ of size 8 at 0x602000000030 thread T0
    #0 0x556fc889953c in ExpressionParser::Expression::~Expression() (.../main.x+0x153c)
    ...
0x602000000030 is located 0 bytes inside of 8-byte region [0x602000000030,0x602000000038)
freed by thread T0 here:
    #0 0x7f5258f6f22f in operator delete(void*, unsigned long) .../libsanitizer/asan/asan_new_delete.cpp:172
    #1 0x556fc889965f in ExpressionParser::Lexer::~Lexer() (.../main.x+0x165f)
    ...
previously allocated by thread T0 here:
    #0 0x7f5258f6e1c7 in operator new(unsigned long) .../libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x556fc8899588 in ExpressionParser::Lexer::tokenize() (.../main.x+0x1588)
    ...
SUMMARY: AddressSanitizer: heap-use-after-free (/home/john/own/C/mp-gmp/const-problem/main-2.x+0x153c) in ExpressionParser::Expression::~Expression()
...

正常输出(去掉const修饰时)

通过编译选项-D CONST=移除const修饰后,程序运行正常,输出如下:

0x602000000010 = new Lexer
0x602000000030 = new Token
0x7ffff44937e0 = new Expression
0x7ffff44937e0 = start delete Expression
0x602000000010 = start delete Lexer
0x602000000030 = delete Token
0x602000000010 = done delete Lexer
0x7ffff44937e0 = end delete Expression

额外现象

添加virtual ~Lexer();声明也能解决问题,但Lexer类原本没有任何虚方法,这一现象令人困惑。

源代码

#include <cstdio>

#ifndef CONST
#define CONST const
#endif

class ExpressionParser
{
public:
    class Token;
    class Lexer;
    class Expression
    {
        friend ExpressionParser;
        Expression (Token *token) : expression_(token)
        {
            printf ("%p = new Expression\n", (void*) this);
        }
        Expression (const Expression&) = delete;
        Expression (Expression&&) = delete;
        void operator= (const Expression&) = delete;
        void operator= (Expression&&) = delete;
        ~Expression();
        Token *expression_;
    };
    static void eval();
};

using EP = ExpressionParser;

class EP::Lexer
{
public:
    Token *tokens_ = nullptr;
    Lexer()
    {
        printf ("%p = new Lexer\n", (void*) this);
    }
    Lexer (const Lexer&) = delete;
    Lexer (Lexer&&) = delete;
    void operator= (const Lexer&) = delete;
    void operator= (Lexer&&) = delete;
    ~Lexer();
    void tokenize();
};

class EP::Token
{
    friend ExpressionParser;
    Lexer * CONST lexer_;
    Token (Lexer *lexer) : lexer_(lexer)
    {
        printf ("%p = new Token\n", (void*) this);
    }
    Token (const Token&) = delete;
    Token (Token&&) = delete;
    void operator= (const Token&) = delete;
    void operator= (Token&&) = delete;
    ~Token()
    {
        printf ("%p = delete Token\n", (void*) this);
    }
};

void EP::eval()
{
    Lexer *lexer = new Lexer();
    lexer->tokenize();
    (void) Expression (lexer->tokens_);
}

EP::Expression::~Expression()
{
    printf ("%p = start delete Expression\n", (void*) this);
    delete expression_->lexer_;
    printf ("%p = end delete Expression\n", (void*) this);
}

void EP::Lexer::tokenize()
{
    tokens_= new Token (this);
}

EP::Lexer::~Lexer()
{
    printf ("%p = start delete Lexer\n", (void*) this);
    delete tokens_;
    printf ("%p = done delete Lexer\n", (void*) this);
}

int main (void)
{
    ExpressionParser::eval();
}

内容的提问来源于stack exchange,提问作者emacs drives me nuts

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 04:55:37