【发布时间】:2018-05-03 14:00:53
【问题描述】:
我正在阅读 BJARNE STROUSTRUP 的好书:编程:使用 C++ 编程的原则和实践。我正在阅读他试图展示如何设计矢量的部分。然而,一句话就抓住了我。 (如果你也在看这本书,我只能告诉你这句话在全书中的位置,不太可能,所以我这里就不定位了。)
“我们通过在未初始化的空间中构造一个副本然后破坏原始的来将一个元素移动到新的空间。我们不能使用赋值,因为对于字符串等类型,赋值假设目标区域已经初始化。”
为了帮助您了解上下文,我在这里提供了一些代码:
template<typename T, typename A = allocator<T>> class my_vector {
A alloc; // use allocate to handle memory for elements
// . . .
private :
T* elem;
int sz;//short for size
int space;//actually means capacity here.
};
他试图展示如何实现reserve()。实现在这里:
template<typename T, typename A>
void my_vector<T,A>::reserve(int newalloc)
{
if (newalloc<=space) return; // never decrease allocation
T* p = alloc.allocate(newalloc); // allocate new space
/***/for (int i=0; i<sz; ++i) alloc.construct(&p[i],elem[i]);// copy!!! he means we can't use copy assignment operator here!
for (int i=0; i<sz; ++i) alloc.destroy(&elem[i]); // destroy
alloc.deallocate(elem,space); // deallocate old space
elem = p;
space = newalloc;
}
他的意思是我们只能使用alloc.construct()复制构造elem,而不是使用简单的复制赋值,例如p[i] = elem[i]。他给出的原因就是我上面引用的。
假设为泛型类型 T 定义了复制赋值(可能使用概念),为什么这里仍然不能使用复制赋值?他说
“如字符串,赋值假设目标区域已经初始化”。
但是,我还是不明白。你能帮我理解他的主旨吗?我认为即使没有启动目标,复制分配也可以正常工作,毕竟目标是要启动的。
谢谢!
【问题讨论】:
-
书中说
std::string的赋值运算符假定目标已初始化。是不相信,还是误会了? (赋值是当你给一个已经存在的东西一个新的值;它不会初始化任何东西。) -
即使在按照当前标准构建然后复制的版本中,也有许多未定义的行为。所以也许这个问题只能以“实用”的方式来回答。当this paper 被接受时,您可能会得到标准确认的答案。
-
@molbdnilo 我明白你的意思。您的意思是构造函数是执行初始化操作的对象,而赋值用于将值分配给已构造的对象。但是为什么我们不能使用一种复制分配的实现,它也进行“初始化”,这意味着不再假设目标已启动?也许是因为性能。但是是否还有其他“不可避免”的原因使得我们必须假设在执行复制分配时启动了目标?还是只是一种使用理念?
-
尝试为执行任何类型的资源管理(如
strings 的vectors 动态存储)并且不需要初始化目标的类实现分配。 (请记住,您无法通过查看某件事来判断它是否存在。)
标签: c++ initialization copy