如何实现此类 C++ 的复制运算符结构?
那么
struct ResultStructure
{
ResultStructure(const ResultStructure& other)
{
// copy code in here ? using memcpy ? how???
}
ResultStructure& operator=(const ResultStructure& other)
{
if (this != &other) {
// copy code in here ?
}
return *this
}
int length;
char* ptr;
};
如何实现“复制构造函数”和“赋值运算符”呢? (抱歉 - 我是 C++ nube)
更新:sbi 和其他人问 - 为什么我要手动处理原始内存?我的答案很简单 - 在我参与的一个学生项目中,我们使用了很多 C 库,例如 OpenCV OpenAL 和 FFmpeg,而且还会有更多库。目前,我们尝试使用 C++ 创建一个基于图形的直接显示类跨平台库,这将有助于实时视频广播和处理。我们的图形元素当前使用 char* 和 int 对进行数据交换。为了将数据转换为订阅元素,我们现在使用原始 memcpy。我想更进一步,使我们能够使我们的图形元素基于 C++ 模板。因此,一个图元素将能够与其他图元素共享当前图元素数据,并且它共享的数据将是一种结构,该结构将不包含一个 char* 一个 int ,而是包含任意数量的数据字段和几乎所有内部元素。所以这就是为什么我需要了解如何创建一个基本的 C++ 结构来实现“复制构造函数”和“赋值运算符”,以便我能够使用新的数据转换算法,例如
void CastData(T item){
for(size_t i = 0 ; i < FuncVec.size(); i++){
T dataCopy = item;
FuncVec[i](dataCopy);
}
}
而不是当前使用的算法
void CastData(char * data, int length){
for(size_t i = 0 ; i < FuncVec.size(); i++){
char* dataCopy = new char[length];
memcpy(dataCopy, data, length);
FuncVec[i](dataCopy, length);
delete[] dataCopy;
}
}
So having
struct ResultStructure
{
ResultStructure(const ResultStructure& other)
{
// copy code in here ? using memcpy ? how???
}
ResultStructure& operator=(const ResultStructure& other)
{
if (this != &other) {
// copy code in here ?
}
return *this
}
int length;
char* ptr;
};
How to implement "copy constructor" and "assignment operator"? (sorry - I am C++ nube)
Update: sbi and others ask - why do I want to manually deal with raw memory? My answer is simple - In a students project I am part of now we use lots of C library's such as for example OpenCV OpenAL and FFmpeg and there are more to come. Currently using C++ we try to create a graph based direct show like cross platform library that would be helpful in live video broadcasting and processing. Our graph elements currently use char* and int pairs for data exchange. To cast data to subscribed elements we use raw memcpy now. I want to go further and make it possible for us to make our graph elements base C++ template. So that one graph element would be capable of of sharing current graph element data with other Graph elements and that data it shares would be a structure that would contain not one char* one int but any number of data fields and nearly any elements inside. So that is why I need to understand how to create a basic C++ structure that implements "copy constructor" and "assignment operator" for me to be capable to use new for us data casting algorithms like
void CastData(T item){
for(size_t i = 0 ; i < FuncVec.size(); i++){
T dataCopy = item;
FuncVec[i](dataCopy);
}
}
instead of currently used
void CastData(char * data, int length){
for(size_t i = 0 ; i < FuncVec.size(); i++){
char* dataCopy = new char[length];
memcpy(dataCopy, data, length);
FuncVec[i](dataCopy, length);
delete[] dataCopy;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您可能想要解释为什么要手动处理原始内存。我已经很长时间没有这样做了,这就是
std::string
和std::vector
的设计目的:但如果你真的需要这样做,那就很难了方式(这是作业吗?),然后请注意,一开始要做好这项工作是非常困难的。例如,赋值运算符的简单实现可能如下所示:
如果有人意外地将一个对象分配给自身(如果您只有两个引用并且您不怀疑它们引用同一个对象,则可能会发生这种情况),那么这将致命地失败。
另外,如果 new 抛出异常怎么办? (如果内存耗尽,它可能会抛出
std::bad_alloc
。)然后我们已经删除了旧数据并且没有分配新数据。然而,指针仍然指向旧数据曾经所在的位置(实际上,我认为这是实现定义的,但我还没有看到在删除时更改 ptr 的实现)和类的析构函数(您< em>知道该类需要析构函数,对吗?)然后会尝试删除未分配数据的地址处的数据。这就是未定义的行为。您所能期望的最好结果就是它立即崩溃。最简单的方法是使用 Copy-And-交换习惯用法:
请注意,我添加了一个析构函数,更改了赋值运算符以传递每个副本的参数(我们需要调用复制构造函数来分配内存),并添加了一个
swap
成员函数。按照惯例,swap()
函数永远不会抛出异常,而且速度很快,最好是 O(1)。我知道GMan 对复制和交换习惯用法的讨论已经足够详尽,而且令人筋疲力尽,而我的对您来说可能太简洁了,一开始您可能无法理解其中的很多内容,但请尝试坚持并尽可能多地理解。
You might want to explain why you want to manually deal with raw memory. I haven't done this in a long time, it's what
std::string
andstd::vector
where designed for:But if you really need to do this the hard way (is this homework?), then be advised that it is, at first, surprisingly hard to get this right. For example, a naive implementation of the assignment operator might be like this:
If someone accidentally assigns an object to itself (which might happen if all you have is two references and you don't suspect them to refer to the same object), then this will fail fatally.
Also, what if
new
throws an exception? (It might throwstd::bad_alloc
if memory is exhausted.) Then we have already deleted the old data and have not allocated new data. The pointer, however, still points at where the old data used to be (actually, I think this is implementation-defined, but I have yet to see an implementation that changes a ptr upon deletion), and the class' destructor (you knew that class would need a destructor, right?) would then attempt to delete a piece of data at an address where no data is allocated. That's Undefined Behavior. The best you can hope for is that it crashes immediately.The easiest way to do this is to employ the Copy-And-Swap idiom:
Note that I have added a destructor, changed the assignment operator to pass the argument per copy (we need the copy constructor invoked to allocate memory), and added a
swap
member function. Per convention aswap()
function never throws and is fast, preferably O(1).I know that GMan's discussion of the Copy-And-Swap idiom is exhaustive enough to be and exhausting while mine is probably too terse for you, and you will likely not understand a lot of it at first, but try to persevere and to understand as much as possible.
如果您使用
std::string
,而不是char*
,您甚至不需要编写operator=
或复制构造函数。编译器生成的代码可以很好地完成您的工作。但作为一般解决方案(对于其他场景),请使用复制和交换习惯用法:
卓越的 C++ by <赫伯·萨特(Herb Sutter)对此进行了非常详细的描述。我建议您阅读本书中的内容。目前,您可以在线阅读这篇文章:
If you use
std::string
, instead ofchar*
, you would not even need to writeoperator=
or copy-constructor. The compiler generated code would do your job very well.But as a general solution (for some other scenario), use copy-and-swap idiom:
Exceptional C++ by Herb Sutter has described these in great detail. I would recommend you to read items from this book. For the time being, you can read this article online:
简单的解决方案是使用
std::string
而不是char*
成员。然后编译器生成的复制构造函数和复制赋值运算符就可以工作了。
一般来说,特别是作为新手,不要有原始指针成员。
干杯&呵呵,
The easy solution is to use a
std::string
instead ofchar*
member.Then the compiler-generated copy constructor and copy assignment operator just work.
As a rule, and especially as a novice, don't have raw pointer members.
Cheers & hth.,
正如已经说过的,正如在问题中所建议的那样,您可能应该重用现有的容器。至少代码是正确的:)
不过出于教育目的,让我们检查一下这个结构:
在这里,我们需要显式的内存管理。值得注意的是,这意味着遵循三规则(感谢 Fred)
让我们从实际构建我们的对象开始:
现在我们可以实现传统的运算符:
As has been said, and as was recommending in the question this emanated from, you should probably reuse an existing container. At least the code would be right :)
For educational purposes though, let's examine this structure:
Here, we need explicit memory management. This implies, notably, following the Rule Of Three (say thanks to Fred)
Let's begin with actually building our object:
Now we can implement the traditional operators:
这是 std::vector的工作 - 或者这是家庭作业?
该向量将替换
length
和ptr
后面的分配。向量是 C++ 习惯用法,如果您像所描述的那样实现类,您将不会与其他 C++ 开发人员交朋友。当然,也有一些特殊情况,但矢量等标准容器是默认的。向量知道如何复制字符以及它本身,并且实现经过优化和测试。
以下是如何使用向量显式实现复制构造函数/赋值:
this is
std::vector<char>
's job - or is this homework?the vector would replace both
length
and the allocation behindptr
. the vector is the c++ idiom, and you'll not make friends with other c++ devs if you implement your classes like you've described. of course, there are corner cases, but standard containers such as vector are the default.the vector knows how to copy chars as well as itself, and the implementations are optimized and tested.
here's how to explicitly implement copy ctor/assign using a vector:
我认为这应该可以完成工作:
请记住在析构函数中释放 ptr 。
ptr下存储了什么?如果是文本,为什么不使用 std::string ?无论如何你可以使用 std::vector 。那么构造函数就会容易得多......
I think this should do the work:
Please remember about freeing ptr in destructor.
What is stored under ptr? If text, why not to use std::string? Anyway you can use std::vector. The constructors will be much easier then...
ptr
指向的内存是如何分配的?如果使用 new,则使用
new
进行分配,设置length
,然后复制如果使用
malloc
分配内存,请替换对的调用>malloc
代替对new
的调用。如果您正在使用其他内存方案,请弄清楚。 :)How is the memory to which
ptr
points allocated?if using new, allocate with
new
, setlength
and then copyIf you're allocating the memory with
malloc
, substitute a call tomalloc
in place of the call tonew
. If you're using some other memory scheme, figure it out. :)