我的任务是实现一个覆盖=运算符的方法。我写了一些东西,但说实话,我不知道我在做什么。有人可以解释这样做的重点是什么(不是一般,我理解,但只是在这种情况下,我有点困惑)?我的方法应该完成什么?我的逻辑在我当前的代码中失败了什么?
scene.cpp:70: error: no match for ‘operator=’ in ‘*(((Image*)(((long unsigned int)i) * 80ul)) + newArray) = *(((Scene*)this)->Scene::images + ((Image**)(((long unsigned int)i) * 8ul)))’
答案 0 :(得分:1)
在管理内存的类中实现复制构造函数或赋值运算符并保持代码异常安全是非常棘手的。异常安全意味着确保在程序中的任何位置抛出异常时,仍然可以正确清理手动管理的内存。一些成语出现了帮助:
RAII的基本租户是,如果你必须管理内存(最近经常这样做,你没有),将内存处理包装在一个对象中,该对象在构造时只分配一块内存,并在销毁时释放内存复制和交换是在必须处理内存分配时实现非平凡赋值运算符的具体指导。这是您尝试解决的确切方案。
我建议您在继续尝试编写管理内存的代码之前阅读相关内容,或者您可能会试图压扁所有错误。
自己实现习语的另一种方法是依靠std::vector
和tr1::shared_ptr
等代码为您进行内存管理。很多从内到外都了解C ++和内存管理怪异的人经常使用这两者。你可以经常逃脱这些。
答案 1 :(得分:1)
你的(内部)代码用英语做什么:
//allocate new memory and copy
images = new Image*[source.maximum];
这会将images
设置为新分配的source.maximum
未初始化Image
指针数组。无论images
指向什么都丢失了。
Scene(source);
这将创建一个新的临时Scene
对象,然后将其抛弃。它不会“重新调用”this
上的构造函数。
//deallocate old memory
delete *source;
如果它有效,则会取消引用source
(const Scene&
,因此只有在定义T* Scene::operator *(void)
时才有效,其中T
属于某种类型)删除指向的T
对象。
//assign
source=images;
这会尝试将images
复制到source
上,这不应该发生,因为source
是const
。创建后,无法更改引用以引用其他对象。
this->maximum=images.maximum;
这不起作用。 images
是Image**
,没有maximum
字段。此外,this->
是多余的。
更新:关于新版本:
首先,您无需在任何地方说this->
。
for (int i=0;i<source.maximum;i++)
this->images[i]=source->images[i];
此处的问题是source
是引用,而不是指针,因此您应该使用source.images[i]
而不是source->images[i]
。
假设这是固定的,现在的问题是当前对象和source
都指向图像对象。如果任一对象释放内存(delete images[i]; images[i] = 0;
或类似内容),则另一个对象中的指针变为无效。 如果图片永远不会删除,则此代码就可以了。
但是,如果您希望此对象拥有自己的图像副本,那么您需要做更多的工作:
if(this != &source)
{
// Delete old images.
for(int i = 0; i < maximum; i++)
delete images[i];
delete[] images;
// Copy new images.
maximum = source.maximum;
images = new Image*[maximum];
for(int i = 0; i < maximum; i++)
images[i] = new Image(*(source.images[i]));
}
这假设您有Image
(Image::Image(const Image&);
)的复制构造函数。
最后,Scene
应该有一个类似于这个的复制构造函数,除了它不需要删除旧的东西。如果您不制作图像副本,请使用:
Scene::Scene(const Scene& original): maximum(original.maximum)
{
images = new Image*[maximum];
for(size_t i = 0; i < maximum; i++)
images[i] = source.images[i];
}
如果您执行制作图像副本,请使用:
Scene::Scene(const Scene& original): maximum(original.maximum)
{
images = new Image*[maximum];
for(size_t i = 0; i < maximum; i++)
images[i] = new Image(*(source.images[i]));
}
在这两种情况下,不要忘记将Scene(const Scene& original);
添加到类定义中。
答案 2 :(得分:0)
覆盖一个operater就像现在重载一个函数一样;你可以通过= op。
复制一份Scene A; Scene B; A.do_things(); B = A;
如果你没有重载=运算符; B = A会使B指向与A相同的对象(因为C中的类实例变量是指针)。
答案 3 :(得分:0)
不太确定你想要它做什么。但它有很多错误
通常情况下,operator =会获取原件的副本而不对原件进行任何更改。
看起来您希望将图像的所有权从一个对象转移到另一个对象。
delete * source只是危险,因为它不是/不应该是所有者。 source很容易成为堆栈变量。
源!=图像所以将图像分配给源只是为了杀死事物
将图像存储在矢量中将处理分配内存以及为您复制所有图像。
答案 4 :(得分:0)
您的代码存在一些问题。
delete source
,你把它作为对const的引用传递给它,所以不要管它!this->images
没有为delete[] images
分配新内存。const
是什么。images
分配给source
。一个是你不应该(不能)分配给source
。另一个原因是,除非Scene
是Image
,否则您无法将Image
分配给Scene
指针。答案 5 :(得分:0)
实现一个非平凡的赋值运算符有一个规范的解决方案:
Scene const & Scene::operator=(Scene s) { swap(s); return *this; }
void Scene::swap(Scene & s) /* nothrow */ {
Image *temp_images = images; images = s.images; s.images = temp_images;
int temp_maximum = maximum; maximum = s.maximum; s.maximum = temp_maximum;
}
这完全是异常安全的,因为它依赖于复制构造函数来创建源的临时副本,然后将其交换(使用无抛出交换)来替换目标。如果副本的任何部分出错,源和目标都将保持不变。
唯一不做的是优化自我分配。然而,它确实在自我分配的情况下正常工作,我通常不会优先考虑不应该发生的事情(在实践中很少会这样做)。
另一种选择是使用更传统的参数类型:
Scene const & Scene::operator=(Scene const & s) {
Scene temp(s);
swap(temp);
return *this;
}
然而,除了更加冗长之外,这个版本的效率可能更低,因为它保证了副本的制作,而传递给s的参数如果传递给s的参数是rvalue,则可能会忽略副本。 / p>