对于某些数据类型 std::vector<std::auto_ptr<T>>
,std::vector<std::unique_ptr<T>>
可以编译但无法正确执行,而带有 T
的相同程序可以正确编译和运行,这样的简单 C++ 程序是什么?< /p>
我知道 std::auto_ptr
已被弃用或删除;我只想要一个涉及容器的例子来激励为什么它被弃用或删除。
我在 MacOS Big Sur 11.2.1 版上使用 g++-10 -std=c++20
。
答案 0 :(得分:6)
std::auto_ptr
根本不能在标准容器中使用。在这种情况下,它不会保持正确的语义。这就是为什么首先在 C++11 中发明移动语义和 std::unique_ptr
的原因之一。 std::auto_ptr
在 C++11 中已弃用,并在 C++17 中完全删除。所以不要在现代编码中使用它。
此处详细说明了 std::auto_ptr
被弃用的官方原因:
给出的示例在 std::sort()
上使用 std::vector<std::auto_ptr<int>>
:
通过这样的设计,可以将 auto_ptr 放入容器中:
vector<auto_ptr<int> > vec;
然而,这种设计的现场经验揭示了一些微妙的问题。即:
sort(vec.begin(), vec.end(), indirect_less());
根据 sort
的实现,上面这行看起来合理的代码可能会也可能不会按预期执行,甚至可能崩溃!问题是 sort
的某些实现会从序列中挑选一个元素,并存储它的本地副本。
...
value_type pivot_element = *mid_point;
...
算法假定在此构造之后 pivot_element
和 *mid_point
是等效的。然而,当 value_type
变成 auto_ptr
时,这个假设失败了,随后算法也失败了。
解决此问题的方法是通过禁止从 auto_ptr
进行“复制”,使 const auto_ptr
不适合容器。使用这样的 auto_ptr
,如果您尝试将其放入容器中,则会出现编译时错误。
最后的结论是这样的:
<块引用>调用任何对 std
进行操作的泛型代码,无论是否为 auto_ptr
都是有风险的,因为泛型代码可能会假设一些看起来像复制操作的东西,实际上是 em> 复制操作。
结论:
不应使用复制语法从左值移动。应改用其他移动语法。否则通用代码可能会在需要复制时启动移动。
auto_ptr
使用复制语法从左值移出,因此从根本上是不安全的。
答案 1 :(得分:0)
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<select id="race" name="races" class="select2 select2-hidden-accessible" multiple="" data-select2-id="race" tabindex="-1" aria-hidden="true">
<option value="RACE_AI_AN" data-select2-id="41">American Indian or Alaska Native</option>
<option value="RACE_ASIAN" data-select2-id="42">Asian</option>
<option value="RACE_BL_AA" data-select2-id="43">Black or African American</option>
<option value="RACE_NH_PI" data-select2-id="44">Native Hawaiian or Other Pacific Islander</option>
<option value="RACE_WHITE" data-select2-id="45">White</option>
</select>
<br>
<select id="gender" name="gender" class="select2 select2-hidden-accessible" data-select2-id="gender" tabindex="-1" aria-hidden="true">
<option value="" data-select2-id="28">Gender</option>
<option value="GENDER_MALE">Male</option>
<option value="GENDER_FEMALE">Female</option>
<option value="GENDER_OTHER">Another Designation</option>
</select>
的问题在于它可以被复制并且复制会修改原始:
auto_ptr
这与移动现在所做的类似,只是在 a = b; // transfers ownership from b to a
时,语言中没有移动语义。现在 C++ 有了移动语义的所有权转移可以更清楚地表达:
auto_ptr
没有人会/不应该期望该行中的 a = std::move(b);
不会被修改。
然而,对于 b
,通常假设 a = b
不会被修改。 b
打破了这个假设。考虑例如:
auto_ptr
使用 template <typename P>
void foo() {
std::vector<P> x;
x.resize(42);
int i=0;
for (auto& e : x) e.reset(new int(i++));
for (auto e : x) {
std::cout << *e << "\n";
}
for (auto e : x) {
std::cout << *e << "\n";
}
}
这将导致 a compiler error:
P=std::unique_ptr<int>
虽然它使用 <source>:17:15: error: call to deleted constructor of 'std::unique_ptr<int, std::default_delete<int> >'
for (auto e : x) {
^ ~
编译但是是未定义的行为(例如这里的段错误:https://godbolt.org/z/93hdse),因为它取消引用空指针。
任何算法的类似问题都假定复制元素“可以”。例如,按值接受参数的 P=std::auto_ptr<int>
比较器确实可以编译但会造成严重破坏:
auto_ptr
复制的过程并不总是那么明显,当元素可复制时,算法可能会在内部复制元素。