【问题标题】:Undo/redo in C++ Android memory leakC++ Android内存泄漏中的撤消/重做
【发布时间】:2018-08-27 15:01:17
【问题描述】:

我正在 Android 上开发一个手指绘画应用程序。我用 C++ 和卷页一起实现了这个手指画。手指画效果很好,但我想知道我的 undoPen 和 redoPen 方法是否存在内存泄漏。它必须使用原始指针来完成。我只添加了代码的有用部分。

vector<vector<*mPath>>MAIN(12);
vector<*mPath> undoMain(0);
int PageNo = 0;
void Pen::onFingerDown(float x1, float y1)
{
    undoMain.clear();

    MAIN[PageNo].push_back(move(path));
    mx = x1;
    my = y1;
    tempPoints.x1=x1;
    tempPoints.y1=y1;
    tempPoints.x2=x1;
    tempPoints.y2=y1;
    // points.push_back(tempPoints);
    path->addVert(tempPoints);
}

void Pen::onFingerMove(float x, float y)
{
    tempPoints.x1=mx;
    tempPoints.y1=my;
    tempPoints.x2=x;
    tempPoints.y2=y;
    path->addVert(tempPoints);

    // path->addColor(tempColors);
    // points.push_back(tempPoints);

    mx=x;
    my=y;
    //LOG_INFO("LOOOOOL");
}

void Pen::onFingerUp()
{
    path = new mPath();
}

void Pen::undoPen()
{
    if (MAIN[PageNo].size()>0) {
        undoMain.push_back(move(*MAIN[PageNo].erase(MAIN[PageNo].end()-1)));
    }

}

void Pen::redoPen()
{
    if (undoMain.size()>0) {
        MAIN[PageNo].push_back(move(*undoMain.erase(undoMain.end()-1)));

        ////
    }
}

【问题讨论】:

  • 这段代码能编译吗? vector&lt;vector&lt;*mPath&gt;&gt;MAIN(12); 语法无效。
  • 在显示的代码中有 1 次调用 new 和 0 次调用 delete。所以你要么有泄漏,要么有更多我们需要查看的代码。
  • 有很多工具可以发现内存泄漏。以valgrind 为例。
  • Yes NathanOliver 代码编译。理查德路径变量在类的解构函数中被删除我的主要问题是 undoPen 和 redoPen 方法是否存在内存泄漏。

标签: android c++ memory-leaks


【解决方案1】:

我没有仔细阅读您的代码,但是当您在没有相应的隐式或显式删除的情况下调用 new 时当然会发生内存泄漏,让我们为此目的使用智能指针。此外:

 vector<vector<PathType>>MAIN(12); // *mPath should be a type, what is the type of mPath 
 vector<PathType> undoMain(0);

我会这样做

 vector<vector<std::unique_ptr<PathType>>>MAIN(12); // 
 vector<std::unique_ptr<PathType>> undoMain(0);

或者如果 MAIN 和 undo undoMAIN 共享相同的数据

vector<vector<std::shared_ptr<PathType>>>MAIN(12); // 
vector<std::shared_ptr<PathType>> undoMain(0);

您的示例代码中实际上没有定义路径

编辑:

我一直在修改我的答案。

首先,也许您应该继续学习和深入研究 C++,忘记托管代码,您的版本令人困惑。事实上我们不会使用智能指针,一切都可以复制而没有太多副作用:

我给你一个修改后的版本:

    typedef vector < fingerPos >            path_type;          // So you low level representation of a path

// Those two must have finite limits ( no more than a given configuration dependant number )
std::deque < path_type >            undo_History  ( 12 );   // no need to reserve anything here ( although you can ), user input are slow.
std::deque < path_type >            redo_History   ( 12 )

struct Path 
{
    path_type                       mlineHolder;

    Path() 
    { } 

    void addVert ( fingerPos vert ) 
    { 
        mlineHolder.push_back(vert); 
    }  

    vector < fingerPos > Path::getPath ( ) 
    { 
        return ( mlineHolder ); 
    }

    ~Path() 
    { 
        // no need it's automatic 
        // mlineHolder.clear();

        // copy the current path to the Undo buffer
        undo_History.push_back ( mlineHolder );     
    } 
};

void Pen::onFingerDown(float x1, float y1)
{
    // Don't undo when user begins a new drawing or you loose your buffers
    // undoMain.clear ( );

    // But clear the redo history since you cannot redo from something different
    redo_History.clear ( );

    mx = x1;
    my = y1;

    tempPoints.x1=x1;
    tempPoints.y1=y1;
    tempPoints.x2=x1;
    tempPoints.y2=y1;

    // points.push_back(tempPoints);
    m_path->addVert ( tempPoints );
}

void Pen::onFingerMove(float x, float y)
{
    tempPoints.x1=mx;
    tempPoints.y1=my;
    tempPoints.x2=x;
    tempPoints.y2=y;

    m_path->addVert(tempPoints);

    // path->addColor(tempColors);
    // points.push_back(tempPoints);

    mx=x;
    my=y;
    //LOG_INFO("LOOOOOL");
}

void Pen::onFingerUp ( )
{
    UndoHistory.push_front ( std::move ( m_path ) );
    // Also add this path to the global structure holding every primitives on screen

}


// Undo should not be part of pen but the top level drawing manager.
void Manager::undo ( )
{
    if ( UndoHistory.size  ( )  ) {
        redo_History. push_front ( undoMain.back ( );
    }

    // then redraw everything form the begining of undo history
    // You must have something holding every primitives on screen that is deeper than redo history
    ...
}

void Pen::redoPen ( )
{
    if  ( redo_History .size ( ) > 0 ) {
        Undo_History. push_front ( RedoMain.back ( );
        // Also add this path to the global structure holding every primitives on screen
    }

    // then redraw everything form the begining then everything from begin to end of undo history
}

确实,向任何事物添加撤消历史记录并不是那么容易。您必须深入了解您的图形引擎。

希望这能有所帮助。

【讨论】:

  • mPath 实际上是一个持有浮点数的类。下面是 mPath 类,请您输入如何使用 shared_ptr 完成撤消和重做。
  • mPath::mPath() { } //// mPath::~mPath() { mlineHolder.clear(); // vector(mlineHolder).swap(mlineHolder); } /// void mPath::addVert(fingerPos vert) { mlineHolder.push_back(vert); } /// vector mPath::getPath() { return mlineHolder; }
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-06
  • 2013-06-15
  • 2011-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多