最近我有建议span<T>在我的代码中使用's,或者在网站上看到了一些使用span's - 应该是某种容器的答案.但是 - 我在C++标准库中找不到类似的东西.
那么这个神秘的是什么span<T>,以及为什么(或什么时候)使用它是一个好主意,如果它是非标准的?
我不确定以下代码是否会导致冗余计算,还是特定于编译器?
for (int i = 0; i < strlen(ss); ++i)
{
// blabla
}
Run Code Online (Sandbox Code Playgroud)
strlen()每次i增加时会计算出来吗?
我正在观看Chandler Carruth在CppCon 2019中的演讲:
在该示例中,他举例说明了您对使用std::unique_ptr<int>over和会产生多少开销而感到惊讶int*。该段大约在时间点17:25开始。
您可以看一下他的示例代码对(godbolt.org)的编译结果 -可以看到,确实,编译器似乎不愿意传递unique_ptr值-实际上,底线是只是一个地址-在寄存器内,仅在直接内存中。
Carruth先生在27:00左右提出的观点之一是,C ++ ABI要求按值传递参数(某些但不是全部;也许-非基本类型?而不是在寄存器中。
我的问题:
PS-为了不给这个问题留下代码:
普通指针:
void bar(int* ptr) noexcept;
void baz(int* ptr) noexcept;
void foo(int* ptr) noexcept {
if (*ptr > 42) {
bar(ptr);
*ptr = 42;
}
baz(ptr);
}
Run Code Online (Sandbox Code Playgroud)
唯一指针:
using std::unique_ptr;
void bar(int* ptr) noexcept;
void baz(unique_ptr<int> ptr) noexcept;
void foo(unique_ptr<int> ptr) noexcept {
if (*ptr > 42) {
bar(ptr.get());
*ptr = 42;
}
baz(std::move(ptr));
}
Run Code Online (Sandbox Code Playgroud) 我最近在CppCon 2016上观看了Herb Sutter关于"Leak Free C++ ..."的精彩演讲,他谈到了使用智能指针实现RAII(资源获取是初始化) - 概念以及它们如何解决大多数内存泄漏问题.
现在我在想.如果我严格遵循RAII规则,这似乎是一件好事,为什么这与C++中的垃圾收集器有什么不同呢?我知道使用RAII,程序员可以完全控制何时再次释放资源,但是在任何情况下都只对垃圾收集器有益吗?它的效率真的会降低吗?我甚至听说有一个垃圾收集器可以更高效,因为它可以一次释放更大的内存块,而不是在代码中释放小内存块.
什么免费和商业垃圾收集库可用于C++,每个库的优缺点是什么?
我对来自该领域实际使用的来之不易的教训感兴趣,而不是营销或宣传模糊.
没有必要详细说明与自动垃圾收集相关的常规权衡,但请提及所使用的算法(引用计数,标记和扫描,增量等)并简要总结后果.
对垃圾收集和基于可达性的泄漏检测的最小支持
(但似乎没有在GCC和Clang中实施.)
为什么标准委员会引入了这种垃圾收集C++ langauge功能?
C++真的需要GC吗?RAII不是一个优秀的模式(可以统一用于内存和非内存资源,如套接字,文件,纹理......)?
GC会破坏使用RAII的C++代码模式的一致性吗?
有人说GC可以派上用场来打破循环依赖,但是weak_ptr为了这个目的,使用智能指针是不是可以呢?
如果抛出异常会发生什么?如何修改堆栈展开语义以考虑GC?
并且还会IDisposable引入类似C#的模式吗?
此外,假设在C++中引入了GC,指针语法会不同吗?例如,我们是否会^像C++/CLI或C++/CX扩展中那样有类似帽子的"指针" ?应该有一种方法可以区分普通的原始指针和"托管"指针,对吧?
我们最近将我们的消息处理应用程序从Java 7升级到Java 8.自升级以来,我们偶尔会遇到一个流在读取时被关闭的异常.记录显示终结器线程正在调用finalize()保存流的对象(进而关闭流).
代码的基本概要如下:
MIMEWriter writer = new MIMEWriter( out );
in = new InflaterInputStream( databaseBlobInputStream );
MIMEBodyPart attachmentPart = new MIMEBodyPart( in );
writer.writePart( attachmentPart );
Run Code Online (Sandbox Code Playgroud)
MIMEWriter并且MIMEBodyPart是本土MIME/HTTP库的一部分. MIMEBodyPart扩展HTTPMessage,具有以下内容:
public void close() throws IOException
{
if ( m_stream != null )
{
m_stream.close();
}
}
protected void finalize()
{
try
{
close();
}
catch ( final Exception ignored ) { }
}
Run Code Online (Sandbox Code Playgroud)
异常发生在调用链中MIMEWriter.writePart,如下所示:
MIMEWriter.writePart() 写入部件的标题,然后调用 part.writeBodyPartContent( this )MIMEBodyPart.writeBodyPartContent()调用我们的实用工具方法 …C++ 11引入了引用计数的智能指针std::shared_ptr.作为引用计数,这些指针无法自动回收循环数据结构.但是,可以自动收集参考周期,例如Python和PHP.为了将此技术与垃圾收集区分开来,问题的其余部分将其称为循环中断.
鉴于似乎没有为C++添加等效功能的建议,是否有一个根本原因,为什么类似于已经部署在其他语言中的循环断路器不适用std::shared_ptr?
请注意,这个问题不能归结为"为什么没有GC for C++",这已经被问过了.C++ GC通常是指一个自动管理所有动态分配对象的系统,通常使用某种形式的Boehm保守收集器实现.有人指出,这样的收集器不适合RAII.由于垃圾收集器主要管理内存,甚至可能在内存不足之前就被调用,并且C++析构函数管理其他资源,依赖于GC来运行析构函数会在最坏情况下引入非确定性和资源不足.它还指出,在存在更明确和可预测的智能指针的情况下,完全不需要GC.
但是,基于库的智能指针循环断路器(类似于引用计数解释器使用的循环断路器)与通用GC有重要区别:
shared_ptr.这些对象已经参与共享所有权,因此必须处理延迟的析构函数调用,其确切的时间取决于所有权结构.std::enable_shared_from_this.不使用它的对象不必为控制块中的额外空间付费以保存循环断路器元数据.reset().这足以打破循环并自动销毁对象.要求对象提供并清除其强力引用(根据要求),确保循环断路器不会破坏封装.缺乏自动循环中断的建议表明该想法因实际或哲学原因而被拒绝.我很好奇原因是什么.为了完整起见,这里有一些可能的反对意见:
"它会引入循环shared_ptr对象的非确定性破坏." 如果程序员控制了循环断路器的调用,那么它就不是非确定性的.此外,一旦被调用,循环断路器的行为将是可预测的 - 它将破坏所有当前已知的循环.这类似于shared_ptr析构函数在引用计数降至零后如何销毁基础对象,尽管这可能会导致"非确定性"级联的进一步破坏.
"就像任何其他形式的垃圾收集一样,循环断路器会在程序执行中引入暂停." 实现此功能的运行时的经验表明,暂停是最小的,因为GC只处理循环垃圾,所有其他对象都通过引用计数回收.如果永远不会自动调用循环检测器,则循环断路器的"暂停"可能是运行它的可预测结果,类似于破坏大型std::vector运行大量析构函数的方法.(在Python中,循环gc是自动运行的,但有一些API可以在不需要它的代码段暂时禁用它.稍后重新启用GC将获取同时创建的所有循环垃圾.)
"循环断路器是不必要的,因为循环不是那么频繁,可以很容易地避免使用std::weak_ptr." 事实上,循环很容易在许多简单的数据结构中出现 - 例如,一个树,其中孩子有一个指向父项的后向指针,或一个双向链表.在某些情况下,复杂系统中的异质对象之间的循环仅偶尔与某些数据模式形成,并且难以预测和避免.在某些情况下,用弱变量替换哪个指针远非明显.
为什么不能在编译器编写的管理需要进行什么管理中的C++代码(即,使其"CLR兼容")?
也许有一些妥协,比如在某些情况下禁止无效指针等等.但所有这些额外的关键词等等.这些新增内容必须解决的问题是什么?
我对某些方面以及可能难以解决的问题有所了解,但我们将非常感谢一个很好的解释!
假设您具有以下功能:
void doSomething(){
int *data = new int[100];
}
Run Code Online (Sandbox Code Playgroud)
为什么会产生内存泄漏?由于我无法在函数外部访问此变量,为什么每次调用此函数时编译器都不会自行调用delete?
没有垃圾收集器的其他语言背后的原因是什么?
为什么这些其他语言没有内置垃圾收集?为什么程序员有责任收集?
我读过 Rust 的编译器在编译时“插入”内存管理代码,这听起来有点像“编译时垃圾收集”。
这两种想法有什么区别?
我看过Rust 有什么而不是垃圾收集器?但那是关于运行时垃圾收集,而不是编译时。