c++ noob:初始化时避免冗余对象复制的正确方法



我做了一个最小的例子:

#include <iostream>
#include <conio.h>
using namespace std;
// skipped getters and setters and bounds checking for brevity
struct Vertex {
    int x,y;
    Vertex() {
    }
    Vertex(int x, int y) {
        this->x = x;
        this->y = y;
    }
};
struct Polygon {
    Vertex *vertexlist;
    Polygon() {
    }
    Polygon(Vertex *v) {
        vertexlist = new Vertex[4]; //hard coded 4 vertices for example brevity
        for(int i=0;i<4;i++) {
            vertexlist[i] = v[i];
        }
    }
    Vertex& getVertex(int index) const {
        return this->vertexlist[index];
    }
};
struct PolyList {
    Polygon *polylist;
    int lastpoly;
    PolyList() {
        polylist = new Polygon[10]; //hard coded 10 for example brevity
        lastpoly = 0;
    }
    void add(const Polygon& p) {
        polylist[lastpoly++] = p;
    }
};
ostream& operator<<(ostream& o, Vertex& v) {
    return o << "(" << v.x << ", " << v.y << ")";
}
ostream& operator<<(ostream& o, const Polygon& p) {
    for(int i=0;i<4;i++) {
        o << p.getVertex(i) << ", ";
    }
    return o;
}
ostream& operator<<(ostream& o, PolyList& pl) {
    for(int i=0;i<pl.lastpoly;i++) {
        o << pl.polylist[i] << endl;
    }
    return o;
}
int someFunc() {
    Vertex *vl = new Vertex[4];
    PolyList pl;
    vl[0] = Vertex(1,2);
    vl[1] = Vertex(3,4);
    vl[2] = Vertex(5,6);
    vl[3] = Vertex(7,8);
    pl.add(Polygon(vl)); // this Polygon goes out of scope after this line
    cout << pl << endl;
}
int main() {
    someFunc();
}

(所以tl;dr, Polygon是4x Vertex的列表,PolyListPolygon:s的列表。Polygon:s通过实例化临时Polygon,将add()转换为PolyList

现在,这会泄漏内存,因为Polygon中的顶点永远不会被释放。但是,如果我添加析构函数:Polygon::~Polygon(){删除[]顶点}然后cout & lt; & lt;pl & lt; & lt;endl;将不起作用,因为Polygon已经超出了作用域,析构函数释放了顶点。

我可以让PolyList析构函数调用Polygon->free()函数。或者,我可以让Polygon::Polygon(Vertex *v)深度复制v中的所有顶点,然后PolyList::PolyList(Polygon &p)可以深度复制p。

我也可以做一个PolyList::createPolygon(int x1, int y1, int x2, int y2...),但这是在面对OO。

c++中处理这种情况的正确方法是什么?不要介意我的实际示例,在这个示例中内存泄漏不会成为问题,我说的是原则上的问题。如果我创建一个分层对象树,我想复制指针,而不是深度复制对象。

编辑:我正试图深入学习c++,所以这不是关于使用vector<>或另一个"罐装解决方案";这不是我在这里所追求的,尽管我确信如果上面的例子是我遇到的一个实际问题,这是一个很好的解决方案。上面的例子只是我能想到的最简短的例子来解释我的问题。

您可以使用智能指针和STL容器(主要是PaulMcKenzie建议的std::vector)。

他们会帮很多忙的。

使用std::vector

的示例
#include <iostream>
#include <conio.h>
#include <vector>
using namespace std;
// skipped getters and setters and bounds checking for brevity
struct Vertex {
    int x, y;
    Vertex() {
    }
    Vertex(int x, int y) {
        this->x = x;
        this->y = y;
    }
};
typedef vector<Vertex> vertex_list_t;
struct Polygon {
    vertex_list_t vertexlist;
    Polygon() {
    }
    Polygon(vertex_list_t v) {
        //hard coded 4 vertices for example brevity
        for (int i = 0; i<4; i++) {
            vertexlist.push_back(Vertex(i, i));
        }
    }
    Vertex getVertex(int index) const {
        return vertexlist[index];
    }
};
typedef vector<Polygon> polygon_list_t;
ostream& operator<<(ostream& o, Vertex& v) {
    return o << "(" << v.x << ", " << v.y << ")";
}
ostream& operator<<(ostream& o, const Polygon& p) {
    for (auto v: p.vertexlist) {
        o << v << ", ";
    }
    return o;
}
ostream& operator<<(ostream& o, polygon_list_t& pl) {
    for (auto &p : pl) {
        o << p << endl;
    }
    return o;
}
int someFunc() {
    vertex_list_t vl = {
        Vertex(1, 2),
        Vertex(3, 4),
        Vertex(5, 6),
        Vertex(7, 8)
    };
    polygon_list_t pl;
    pl.push_back(Polygon(vl)); // this Polygon goes out of scope after this line
    cout << pl << endl;
    return 0;
}
int main() {
    someFunc();
}

什么是真正的交易?

pl.add(Polygon(vl)); // this Polygon goes out of scope after this line

你传递多边形作为临时的,

$12.2/3- "临时对象在(词法上)包含其创建点的完整表达式(1.9)求值的最后一步被销毁。即使该求值以抛出异常结束,也是如此。"

修改为:

Polygon p1(vl);
pl.add(p1); // this Polygon NOT goes out of scope after this line

您可以使用shared_ptrs作为解决方案。例如

#include "stdafx.h"
#include <iostream>
#include <conio.h>
#include <memory>
#include <list>
#include <vector>
using namespace std;
struct Vertex
{
    int x,y;
    Vertex() : x(0), y(0)
    {
    }
    Vertex(int _x, int _y)
    {
        x = _x;
        y = _y;
    }
};
struct Polygon
{
    vector<Vertex> vertexes;
    Polygon()
    {
    }
    Polygon(Vertex *v)
    {
        const int ELEMS_COUNT = 4;
        vertexes.reserve(ELEMS_COUNT);
        vertexes.insert(vertexes.end(), v, v + ELEMS_COUNT);
    }
    Vertex getVertex(int index) const
    {
        return vertexes[index];
    }
};
typedef shared_ptr<Polygon> PolygonPtr;
struct PolyList
{
    std::list<PolygonPtr> polylist;
    void add(PolygonPtr p)
    {
        polylist.push_back(p);
    }
};
ostream& operator<<(ostream& o, const Vertex& v) {
    return o << "(" << v.x << ", " << v.y << ")";
}
ostream& operator<<(ostream& o, const Polygon& p) {
    for (auto& p : p.vertexes)
    {
        o << p << ", ";
    }
    return o;
}
ostream& operator<<(ostream& o, PolyList& pl) {
    for(auto& p : pl.polylist)
    {
        o << *p << endl;
    }
    return o;
}
int someFunc() {
    Vertex vl[] = {Vertex(1, 2), Vertex(3, 4), Vertex(5, 6), Vertex(7, 8)};
    PolyList pl;
    pl.add(PolygonPtr(new Polygon(vl)));
    cout << pl << endl;
    return 0;
}
int main()
{
    someFunc();
    return 0;
}

最新更新