- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有以下代码:
#include <QApplication>
#include <memory>
#include <QUndoCommand>
#include <QWidget>
class Document
{
public:
Document()
{
qDebug("Document");
}
~Document()
{
qDebug("~Document");
}
QUndoStack mUndostack;
};
class DocumentRepository
{
public:
DocumentRepository()
{
qDebug("DocumentRepository");
}
~DocumentRepository()
{
qDebug("~DocumentRepository");
}
void AddDoc(std::shared_ptr<Document> doc)
{
mDocs.emplace_back(doc);
}
std::vector<std::shared_ptr<Document>> mDocs;
};
class Gui : public QWidget
{
public:
Gui(DocumentRepository& repo)
: mRepo(repo)
{
qDebug("+Gui");
for(int i=0; i<3; i++)
{
CreateDoc();
}
mRepo.mDocs.clear();
qDebug("-Gui");
}
~Gui()
{
qDebug("~Gui");
}
void CreateDoc()
{
auto docPtr = std::make_shared<Document>();
connect(&docPtr->mUndostack, &QUndoStack::cleanChanged, this, [=](bool clean)
{
// Using docPtr here causes a memory leak on the shared_ptr's, the destruct after ~Gui
// but without using docPtr here they destruct before ~Gui as exepected.
QString msg = "cleanChanged doc undo count " + QString::number(docPtr->mUndostack.count());
qDebug(msg.toLatin1());
}, Qt::QueuedConnection);
mRepo.AddDoc(docPtr);
}
DocumentRepository& mRepo;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
DocumentRepository repo;
Gui g(repo);
g.show();
return 0;
}
哪些输出:
DocumentRepository
+Gui
Document
Document
Document
-Gui
~Gui
~Document
~Document
~Document
~DocumentRepository
但是在这里您可以看到 Document
实例在 Gui
实例之后被破坏时被泄漏了。如果您查看评论,您会发现我使用 shared_ptr
将这个问题缩小到信号的 lambda。我想知道为什么会导致泄漏,如何解决?
作为引用,在 lambda 中不使用 shared_ptr
时的“正确”/非泄漏输出是:
DocumentRepository
+Gui
Document
Document
Document
~Document
~Document
~Document
-Gui
~Gui
~DocumentRepository
最佳答案
这是一个有趣的问题,让我们揭开它的神秘面纱:
来自official connect documentation :
The connection will automatically disconnect if the sender is destroyed. However, you should take care that any objects used within the functor are still alive when the signal is emitted.
在您的示例中,您正在复制在 lambda 内部使用时创建的共享指针,否则不会为共享指针创建拷贝。该拷贝自然会增加共享指针内对象的引用计数器。这是来自 shared_ptr 的相应文档:
The ownership of an object can only be shared with another shared_ptr by copy constructing or copy assigning its value to another shared_ptr
现在,让我们区分这两种情况:
当您不复制共享指针时,只有一个对该对象的引用,因此当您的文档存储库完成清除后,不再有对它的引用,因此该对象可以被破坏,假设您在 lambda 函数内没有做任何有用的事情,因此可以被优化掉。
当您复制共享指针时,在 lambad 外部有一个对对象的引用,并且由于共享指针复制,内部也会有一个。现在,Qt 连接语义可确保对象按照上述文档保持事件状态。
因此,当您的 Gui 对象被析构时,它也会进行所有断开连接,并且在此期间,它可以确保不再有对该对象的引用,因此在您的 gui destructor print 语句之后调用析构函数.
您可以通过在此处添加一个额外的打印语句来改进测试代码:
qDebug("+Gui");
for(int i=0; i<3; i++) CreateDoc();
qDebug("+/-Gui");
mRepo.mDocs.clear();
qDebug("-Gui");
这也将明确向您表明文档对象在存储库清除后被破坏,而不是在您创建它们时在方法终止时被破坏。输出将使其更加清晰:
TEMPLATE = app
TARGET = main
QT += widgets
CONFIG += c++11
SOURCES += main.cpp
#include <QApplication>
#include <memory>
#include <QUndoCommand>
#include <QWidget>
#include <QDebug>
struct Document
{
Document() { qDebug("Document"); }
~Document() { qDebug("~Document"); }
QUndoStack mUndostack;
};
struct DocumentRepository
{
DocumentRepository() { qDebug("DocumentRepository"); }
~DocumentRepository() { qDebug("~DocumentRepository"); }
void AddDoc(std::shared_ptr<Document> doc) { mDocs.emplace_back(doc); }
std::vector<std::shared_ptr<Document>> mDocs;
};
struct Gui : public QWidget
{
Gui(DocumentRepository& repo)
: mRepo(repo)
{
qDebug("+Gui");
for(int i=0; i<3; i++) CreateDoc();
qDebug("+/-Gui");
mRepo.mDocs.clear();
qDebug("-Gui");
}
~Gui() { qDebug("~Gui"); }
void CreateDoc()
{
auto docPtr = std::make_shared<Document>();
connect(&docPtr->mUndostack, &QUndoStack::cleanChanged, this, [=](bool) { /* qDebug() << docPtr->mUndostack.count(); */ }, Qt::QueuedConnection);
mRepo.AddDoc(docPtr);
}
DocumentRepository& mRepo;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
DocumentRepository repo;
Gui g(repo);
g.show();
return 0;
}
DocumentRepository
+Gui
Document
Document
Document
+/-Gui
~Document
~Document
~Document
-Gui
~Gui
~DocumentRepository
关于c++ - Qt 信号 lambda 导致 shared_ptr 泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26574960/
可以使用 lambda 和函数创建有序对(Lisp 中的缺点),如 Use of lambda for cons/car/cdr definition in SICP 所示。 它也适用于 Python
我正在尝试从另一个调用一个 AWS lambda 并执行 lambda 链接。这样做的理由是 AWS 不提供来自同一个 S3 存储桶的多个触发器。 我创建了一个带有 s3 触发器的 lambda。第一
根据以下源代码,常规 lambda 似乎可以与扩展 lambda 互换。 fun main(args: Array) { val numbers = listOf(1, 2, 3) f
A Tutorial Introduction to the Lambda Calculus 本文介绍乘法函数 The multiplication of two numbers x and y ca
我想弄清楚如何为下面的表达式绘制语法树。首先,这究竟是如何表现的?看样子是以1和2为参数,如果n是 0,它只会返回 m . 另外,有人可以指出解析树的开始,还是一个例子?我一直找不到一个。 最佳答案
在 C++0x 中,我想知道 lambda 函数的类型是什么。具体来说: #include type1 foo(int x){ return [x](int y)->int{return x * y
我在其中一个职位发布中看到了这个问题,它询问什么是 lambda 函数以及它与高阶函数的关系。我已经知道如何使用 lambda 函数,但不太自信地解释它,所以我做了一点谷歌搜索,发现了这个:What
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
Evaluate (((lambda(x y) (lambda (x) (* x y))) 5 6) 10) in Scheme. 我不知道实际上该怎么做! ((lambda (x y) (+ x x
我正在处理 MyCustomType 的实例集合如下: fun runAll(vararg commands: MyCustomType){ commands.forEach { it.myM
Brian 在他对问题 "Are side effects a good thing?" 的论证中的前提很有趣: computers are von-Neumann machines that are
在 Common Lisp 中,如果我希望两个函数共享状态,我将按如下方式执行 let over lambda: (let ((state 1)) (defun inc-state () (in
Evaluate (((lambda(x y) (lambda (x) (* x y))) 5 6) 10) in Scheme. 我不知道实际上该怎么做! ((lambda (x y) (+ x x
作为lambda calculus wiki说: There are several possible ways to define the natural numbers in lambda cal
我有一个数据类,我需要初始化一些 List .我需要获取 JsonArray 的值(我使用的是 Gson)。 我做了这个函数: private fun arrayToList(data: JsonAr
((lambda () )) 的方案中是否有简写 例如,代替 ((lambda () (define x 1) (display x))) 我希望能够做类似的事情 (empty-lam
我在 Java library 中有以下方法: public void setColumnComparator(final int columnIndex, final Comparator colu
我正在研究一个函数来计算国际象棋游戏中棋子的有效移动。 white-pawn-move 函数有效。当我试图将其概括为任一玩家的棋子 (pawn-move) 时,我遇到了非法函数调用。我已经在 repl
考虑这段代码(在 GCC 和 MSVC 上编译): int main() { auto foo = [](auto p){ typedef decltype(p) p_t;
我正在阅读一个在 lambda 内部使用 lambda 的片段,然后我想通过创建一个虚拟函数来测试它,该函数从文件中读取然后返回最大和最小数字。 这是我想出来的 dummy = lambda path
我是一名优秀的程序员,十分优秀!