将std :: unitialized_copy用于初始化的内存
如果std :: unitialized_copy 用于初始化的内存,则此用途会导致内存泄漏还是不确定的行为?
例如:
std::vector<std::string> u = {"1", "2", "3"};
std::vector<std::string> v = {"4", "5", "6"};
// What happens to the original elements in v?
std::uninitialized_copy(u.begin(), u.end(), v.begin());
If std::uninitialized_copy
is used to an initialized memory, does this use cause a memory leak or an undefined behavior?
For example:
std::vector<std::string> u = {"1", "2", "3"};
std::vector<std::string> v = {"4", "5", "6"};
// What happens to the original elements in v?
std::uninitialized_copy(u.begin(), u.end(), v.begin());
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
TL; DR:不要这样做。
假设您的
std :: String
实现使用SSO 1 (我相信所有现代的都可以泄漏任何内容SSO'ED。此处的任何可能的UB都由
[basic.life]/5
:对我而言,对我来说并不完全清楚什么是“取决于副作用”的内容(您可以庄严地声明您不介意缺乏副作用,并以这种方式摆脱UB吗?没有副作用。
但!如果您启用迭代器调试,那么无论SSO如何,驱动器可能会产生副作用(以某种方式将其通知迭代器应无效)。然后跳过破坏者可能是有问题的。
1 sso =小(或短)字符串优化=不要在堆上分配一个短字符串,而是将其直接嵌入到
std :: String :: String
实例中。TL;DR: Don't do this.
Assuming your
std::string
implementation uses SSO1 (all modern ones do, I believe), then this doesn't leak anything only if the strings are short enough to be SSO'ed.Any possible UB here is governed by
[basic.life]/5
:It's not entirely clear to me what "depending on side effects" entails (can you solemnly declare that you don't mind the lack of side effects, and get rid of UB this way?), but destroying a SSO'ed string should have no side effects.
But! If you enable iterator debugging, then the destructor might get side effects regardless of SSO (to somehow notify the iterators that they should be invalidated). Then skipping the destructor might be problematic.
1 SSO = small (or short) string optimization = not allocating a short string on the heap, and instead embedding it directly into the
std::string
instance.基于 specialized.algorithms.generalss.general ://timsong-cpp.github.io/cppwp/uninitialized.copy“ rel =” nofollow noreferrer“> noritialized.copy.copy 我没有发现任何正式的要求,即目的地范围必须是非正式的。因此,我们可以考虑
std :: Unitialialized_copy
被定义为等同的句子(不包括暗示的例外安全板代码):
我们可以得出结论,
std :: unitialized_copy 不称呼任何destructor或以其他方式关注什么是什么以前位于目的地范围。假设它是未能的,它只是覆盖它。
要弄清楚这在正确性方面意味着什么,我们可以参考 basic.life.life
但是,这使用了“任何取决于副作用的程序”的宽松定义的概念。 “取决于副作用”意味着什么?
如果您的问题是关于
char
或int
的覆盖向量的,则没有问题,因为这些不是类类型,并且没有破坏者,因此没有任何副作用依靠。但是,std :: String
的破坏者可能具有释放资源的效果。std :: basic_string
如果使用用户定义的分配器,则可能会更直接可观察到副作用。请注意,对于包含非类型元素的范围,不需要std :: unitialized_copy
。这些元素允许空置初始化,并简单地将它们复制到使用std :: copy
的非初始化存储是可以的。由于我认为程序的行为不可能取决于
std :: String
的资源的发布,因此我相信上面的代码在定义良好的行为方面是正确的,尽管它可能会泄漏资源。可以说,该行为可能依赖于std :: bad_alloc
最终被抛出,但是std :: string
并不是严格地说要动态分配。但是,如果所使用的元素类型具有可能影响行为的副作用,并且该程序取决于这些效果,那么它将是UB。通常,虽然在某些情况下可以很好地定义它,但显示的代码违反了 raii 是基于的,这是大多数真实程序取决于的基本功能。基于这些理由
std :: Unitialized_copy
不应用于复制已包含类类型对象的范围。Base on specialized.algorithms.general and uninitialized.copy I don't find any formal requirements that the destination range must be uninitialized. As such, we can consider the effect of
std::uninitialized_copy
which is defined as equivalent to the follow (excluding the implied exception safety boilerplate code) :We can conclude that
std::uninitialized_copy
does not call any destructor or otherwise cares about what was previously located in the destination range. It simply overwrites it, assuming it is uninitialized.To figure out what this means in terms of correctness, we can refer to basic.life
This however uses the loosely defined notion of "any program that depends on the side effects of". What does it mean to "depend on the side effects of"?
If your question was about overwriting vectors of
char
orint
there would be no problem, as these are not class types and do not have destructors so there can be no side effects to depend on. Howeverstd::string
's destructor may have the effect of releasing resources.std::basic_string
may have addition, more directly observable side effects if a user defined allocator is used. Note that in the case of a range containing non-class type elementsstd::uninitialized_copy
is not required. These elements allow for vacuous initialization and simply copying them to uninitialized storage withstd::copy
is fine.Since I don't believe it is possible for the behavior of a program to depend on the release of
std::string
's resources, I believe the code above is correct in terms of having well defined behavior, though it may leak resources. An argument could be made that the behavior might rely onstd::bad_alloc
eventually being thrown, butstd::string
isn't strictly speaking required to dynamically allocate. However, if the type of element used had side effects which could influence the behavior, and the program depended on those effects, then it would be UB.In general, while it may be well defined in some cases, the code shown violates assumptions on which RAII is based, which is a fundamental feature most real programs depend on. On these grounds
std::uninitialized_copy
should not be used to copy to a range which already contains objects of class type.C ++中的非初始化的内存是一个不包含有效对象的内存,通过致电
std :: get_temporary_buffer
,std :: aligned_storage
,std :: :aligned_alloc
,std :: malloc
或类似功能。无法确定是否使用对象初始化提供的内存。开发人员必须关心它。编译器消毒剂可以做到,但是它们的内存属性无法用于程序。
std :: Unitialized_copy
期望不可原始的内存,并且没有其他假设。给出初始化的内存可能会导致内存泄漏和未定义的行为。这里专业内存算法
niitialialized_copy 在算法中的算法库中的标准库中
:
result +[0,(last -first))
与[first,last)
不重叠。结果
。Uninitialized memory in C++ is a memory that contain no valid object(s), is obtained by call to
std::get_temporary_buffer
,std::aligned_storage
,std::aligned_alloc
,std::malloc
or similar functions.There is no way to determine if a supplied memory is initialized with objects. Developers must care of it. The compiler sanitizers can do it, but their memory attributes are not available to a program.
std::uninitialized_copy
expects uninitialized memory and makes no other assumptions. Giving an initialized memory to it may result in memory leaks and undefined behavior.Here the specialized memory algorithm
uninitialized_copy
in Algorithms library in the Standard:result +[0, (last - first))
does not overlap with[first, last)
.result
.