如何实现此类 C++ 的复制运算符结构?

发布于 2024-10-14 23:04:33 字数 1322 浏览 6 评论 0原文

那么

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

茶底世界 2024-10-21 23:04:33

您可能想要解释为什么要手动处理原始内存。我已经很长时间没有这样做了,这就是 std::stringstd::vector 的设计目的:

struct ResultStructure
{
    // nothing else needed

    std::string data; // or std::vector<char>
};

但如果你真的需要这样做,那就很难了方式(这是作业吗?),然后请注意,一开始要做好这项工作是非常困难的。例如,赋值运算符的简单实现可能如下所示:

// DON'T TRY THIS AT HOME!!
ResultStructure& ResultStructure::operator=(const ResultStructure& rhs)
{
  delete[] ptr;                               // free old ressource
  ptr = new char[rhs.length];                 // allocate new resourse
  std::copy(rhs.ptr, rhs.ptr+rhs.length, ptr; // copy data
  length = rhs.length;
}

如果有人意外地将一个对象分配给自身(如果您只有两个引用并且您不怀疑它们引用同一个对象,则可能会发生这种情况),那么这将致命地失败。
另外,如果 new 抛出异常怎么办? (如果内存耗尽,它可能会抛出std::bad_alloc。)然后我们已经删除了旧数据并且没有分配新数据。然而,指针仍然指向旧数据曾经所在的位置(实际上,我认为这是实现定义的,但我还没有看到在删除时更改 ptr 的实现)和类的析构函数(您< em>知道该类需要析构函数,对吗?)然后会尝试删除未分配数据的地址处的数据。这就是未定义的行为。您所能期望的最好结果就是它立即崩溃。

最简单的方法是使用 Copy-And-交换习惯用法

struct ResultStructure
{
    ResultStructure(const ResultStructure& other)
     : ptr(new char[rhs.length]), length(rhs.length)
    {
        std::copy(rhs.ptr, rhs.ptr+rhs.length, ptr);
    }

    ~ResultStructure() // your class needs this
    {
      delete[] ptr;
    }

    ResultStructure& operator=(ResultStructure rhs) // note: passed by copy
    {
        this->swap(rhs);
        return *this
    }

    void swap(const ResultStruct& rhs)
    {
      using std::swap;
      swap(length, rhs.length); 
      swap(ptr, rhs.ptr); 
    }

    std::size_t length;
    char* ptr;
};

请注意,我添加了一个析构函数,更改了赋值运算符以传递每个副本的参数(我们需要调用复制构造函数来分配内存),并添加了一个 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 and std::vector where designed for:

struct ResultStructure
{
    // nothing else needed

    std::string data; // or std::vector<char>
};

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:

// DON'T TRY THIS AT HOME!!
ResultStructure& ResultStructure::operator=(const ResultStructure& rhs)
{
  delete[] ptr;                               // free old ressource
  ptr = new char[rhs.length];                 // allocate new resourse
  std::copy(rhs.ptr, rhs.ptr+rhs.length, ptr; // copy data
  length = rhs.length;
}

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 throw std::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:

struct ResultStructure
{
    ResultStructure(const ResultStructure& other)
     : ptr(new char[rhs.length]), length(rhs.length)
    {
        std::copy(rhs.ptr, rhs.ptr+rhs.length, ptr);
    }

    ~ResultStructure() // your class needs this
    {
      delete[] ptr;
    }

    ResultStructure& operator=(ResultStructure rhs) // note: passed by copy
    {
        this->swap(rhs);
        return *this
    }

    void swap(const ResultStruct& rhs)
    {
      using std::swap;
      swap(length, rhs.length); 
      swap(ptr, rhs.ptr); 
    }

    std::size_t length;
    char* ptr;
};

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 a swap() 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.

挽清梦 2024-10-21 23:04:33

如果您使用 std::string,而不是 char*,您甚至不需要编写 operator= 或复制构造函数。编译器生成的代码可以很好地完成您的工作。

但作为一般解决方案(对于其他场景),请使用复制和交换习惯用法:

卓越的 C++ by <赫伯·萨特(Herb Sutter)对此进行了非常详细的描述。我建议您阅读本书中的内容。目前,您可以在线阅读这篇文章:

If you use std::string, instead of char*, you would not even need to write operator= 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:

时光倒影 2024-10-21 23:04:33

简单的解决方案是使用 std::string 而不是 char* 成员。

然后编译器生成的复制构造函数和复制赋值运算符就可以工作了。

一般来说,特别是作为新手,不要有原始指针成员。

干杯&呵呵,

The easy solution is to use a std::string instead of char* 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.,

转角预定愛 2024-10-21 23:04:33

正如已经说过的,正如在问题中所建议的那样,您可能应该重用现有的容器。至少代码是正确的:)

不过出于教育目的,让我们检查一下这个结构:

class Result
{
public:

private:
  size_t length; // can't really be negative, right ?
  char* data;
};

在这里,我们需要显式的内存管理。值得注意的是,这意味着遵循三规则(感谢 Fred)

让我们从实际构建我们的对象开始:

Result::Result(): length(0), data(0) {}

Result::Result(size_t l, char* d): length(0), data(0)
{
  if (!d) { return; }

  data = new char[l]; // this may throw, so we do it first

  length = l;
  memcpy(data, d, l);
}

现在我们可以实现传统的运算符:

// Swap
void Result::swap(Result& other)
{
  using std::swap;

  swap(length, other.length);
  swap(data, other.data);
}

// Copy Constructor
Result::Result(Result const& other): length(0), data(0)
{
  if (!other.length) { return; }

  data = new char[other.length];
  length = other.length;
  mempcy(data, other.data, length);
}

// Assignemt Operator
Result& Result::operator=(Result other)
{
  this->swap(other);
  return *this;
}

// !IMPORTANT!
// Destructor
Result::~Result()
{
  delete[] data; // use the array form of delete
                 // no need to test for nullity, it's handled
}

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:

class Result
{
public:

private:
  size_t length; // can't really be negative, right ?
  char* data;
};

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:

Result::Result(): length(0), data(0) {}

Result::Result(size_t l, char* d): length(0), data(0)
{
  if (!d) { return; }

  data = new char[l]; // this may throw, so we do it first

  length = l;
  memcpy(data, d, l);
}

Now we can implement the traditional operators:

// Swap
void Result::swap(Result& other)
{
  using std::swap;

  swap(length, other.length);
  swap(data, other.data);
}

// Copy Constructor
Result::Result(Result const& other): length(0), data(0)
{
  if (!other.length) { return; }

  data = new char[other.length];
  length = other.length;
  mempcy(data, other.data, length);
}

// Assignemt Operator
Result& Result::operator=(Result other)
{
  this->swap(other);
  return *this;
}

// !IMPORTANT!
// Destructor
Result::~Result()
{
  delete[] data; // use the array form of delete
                 // no need to test for nullity, it's handled
}
魔法少女 2024-10-21 23:04:33

这是 std::vector的工作 - 或者这是家庭作业?

该向量将替换 lengthptr 后面的分配。向量是 C++ 习惯用法,如果您像所描述的那样实现类,您将不会与其他 C++ 开发人员交朋友。当然,也有一些特殊情况,但矢量等标准容器是默认的。

向量知道如何复制字符以及它本身,并且实现经过优化和测试。

以下是如何使用向量显式实现复制构造函数/赋值:

struct ResultStructure {
    ResultStructure(const ResultStructure& other) : d_chars(other.d_chars) {
    }

    ResultStructure& operator=(const ResultStructure& other) {
        if (this != &other) {
            this->d_chars = other.d_chars;
        }
        return *this;
    }
    std::vector<char> d_chars;
};

this is std::vector<char>'s job - or is this homework?

the vector would replace both length and the allocation behind ptr. 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:

struct ResultStructure {
    ResultStructure(const ResultStructure& other) : d_chars(other.d_chars) {
    }

    ResultStructure& operator=(const ResultStructure& other) {
        if (this != &other) {
            this->d_chars = other.d_chars;
        }
        return *this;
    }
    std::vector<char> d_chars;
};
玻璃人 2024-10-21 23:04:33

我认为这应该可以完成工作:

struct ResultStructure
{
    ResultStructure(const ResultStructure& other);
    ResultStructure& operator=(const ResultStructure& other);

    int length;
    char* ptr;
};

ResultStructure::ResultStructure(const ResultStructure& other):length(other.length)
{
    ptr = (char*)malloc(length);
    memcpy(ptr, other.ptr, length);
}

ResultStructure& ResultStructure::operator=(const ResultStructure& other)
{
    length = other.length;
    ptr = (char*)malloc(length);
    memcpy(ptr, other.ptr, length);
    return *this;
}

请记住在析构函数中释放 ptr 。
ptr下存储了什么?如果是文本,为什么不使用 std::string ?无论如何你可以使用 std::vector 。那么构造函数就会容易得多......

I think this should do the work:

struct ResultStructure
{
    ResultStructure(const ResultStructure& other);
    ResultStructure& operator=(const ResultStructure& other);

    int length;
    char* ptr;
};

ResultStructure::ResultStructure(const ResultStructure& other):length(other.length)
{
    ptr = (char*)malloc(length);
    memcpy(ptr, other.ptr, length);
}

ResultStructure& ResultStructure::operator=(const ResultStructure& other)
{
    length = other.length;
    ptr = (char*)malloc(length);
    memcpy(ptr, other.ptr, length);
    return *this;
}

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...

病毒体 2024-10-21 23:04:33

ptr 指向的内存是如何分配的?

如果使用 new,则使用 new 进行分配,设置 length,然后复制

other.length = length;
other.ptr = new char[length];
memcpy( other.ptr, ptr, length );

如果使用 malloc 分配内存,请替换对 的调用>malloc 代替对 new 的调用。如果您正在使用其他内存方案,请弄清楚。 :)

How is the memory to which ptr points allocated?

if using new, allocate with new, set length and then copy

other.length = length;
other.ptr = new char[length];
memcpy( other.ptr, ptr, length );

If you're allocating the memory with malloc, substitute a call to malloc in place of the call to new. If you're using some other memory scheme, figure it out. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文