gpt4 book ai didi

c++ - 替换不可复制、不可移动的对象

转载 作者:行者123 更新时间:2023-11-28 06:42:56 24 4
gpt4 key购买 nike

考虑以下代码:

// A non-copyable, non-movable aggregate
struct Strange
{
const int & i;
char & c;
};

class Container
{
private:
int my_i;
char my_c;
Strange thing;

public:
// Valid, because both `my_i´ and `my_c´ are non-const
// objects to which both references can be bound.
explicit
Container
( )
noexcept
: thing{ my_i , my_c }
{ }

// How could this be implemented?
auto &
operator=
( const Container & that )
noexcept
{
this->my_i = that->my_i;
this->my_c = that->my_c;

// What to do with `thing´?

return *this;
}
};

可能的解决方案

  1. 动态分配Strange对象

    class Container
    {
    private:
    int my_i;
    char my_c;
    Strange * thing;

    public:
    // Note that it isn't exception safe.
    explicit
    Container
    ( )
    : thing(new Strange{ my_i , my_c })
    { }

    auto &
    operator=
    ( const Container & that )
    noexcept
    {
    this->my_i = that->my_i;
    this->my_c = that->my_c;

    delete this->thing;
    this->thing = new Strange { this->my_i , this->my_c };

    return *this;
    }
    };

    问题:

    • 效率不高。
    • 不安全:分配可能会失败并抛出。
    • 危险:必须非常小心不要泄漏内存。

      除了使代码更具可读性之外,使用智能指针(即 std::unique_ptr)只能解决最后一点。

  2. 使用新的展示位置

    class Container
    {
    private:
    int my_i;
    char my_c;
    Strange thing;

    public:
    explicit
    Container
    ( )
    noexcept
    : thing{ my_i , my_c }
    { }

    auto &
    operator=
    ( const Container & that )
    noexcept
    {
    this->my_i = that.my_i;
    this->my_c = that.my_c;

    // Placement new is exception safe, and so is
    // construction of `Strange´.
    this->thing.~Strange();
    new(&this->thing) Strange { this->my_i , this->my_c };

    return *this;
    }
    };

    问题:

    • Strange 的析构函数会释放 thing 占用的内存吗?

      我认为,就像构造函数一样,析构函数不负责内存管理。此外,我的代码似乎工作正常。不过,我想澄清一下。

    • 内存对齐怎么样?

      我的猜测是,由于它替换了相同类型的现有对象,因此内存已经对齐。这是正确的吗?

    • Container 的析构函数会负责析构 thing 吗?

问题

除了证实和/或反驳我上面解释的担忧之外,我想知道是否还有其他选择。如果是这样,请给出一个示例实现。


这个问题是在处理一个应该提供类似于 std::unordered_map 接口(interface)的类时出现的。我的类没有重新实现它,而是封装了这样的容器,并且只是充当大多数方法的代理:它的迭代器包含映射提供的迭代器,它的对是一个聚合结构,具有适当命名的成员(它们是对实际数据),在提供的示例中表示为Strange。由于需要迭代器返回指向实际数据的引用和指针,因此我的自定义迭代器包含一对。问题在于修改它(在递增或分配迭代器时)。我承认这可能不是一个好主意,而且这些引用影响性能,但无论如何我对此事很感兴趣。

编辑

我刚刚意识到,我可以返回就地构造的自定义对(即 奇怪的对象)。通常,我们看不到我们在一个山洞里,而不是退出它,继续前进:)。打扰一下,我会将问题标记为“已关闭”。

最佳答案

(如果我们谈论移动对象并使用 auto 关键字,您应该将 c++11 标记添加到您的问题中)。

我不确定我是否真的理解你的问题;你举的例子对我来说似乎没有经过深思熟虑;在 Strange 中使用指针会好得多。例如,这个编译和工作绝对正常,并且在功能上等同于我认为你想要做的事情。

struct Strange
{
Strange()
: i(nullptr), c(nullptr) {}
Strange( const int *_i, const char *_c )
: i(_i), c(_c) {}

const int *i;
const char *c;
};

class Container
{
int my_i;
char my_c;
Strange thing;

public:

Container()
: thing(&my_i,&my_c)
{ }

Container( int i, char c )
: my_i(i), my_c(c), thing(&my_i,&my_c)
{ }

Container( int i, char c, const Strange& s )
: my_i(i), my_c(c), thing(s) // use default copy-constructor
{ }

Container &
operator=
( const Container & that )
{
my_i = that.my_i;
my_c = that.my_c;
thing = that.thing;

return *this;
}
};

int main()
{
Container a(12,24);
Container b(25,42);
b = a;
}

请注意,在对象中引用内存通常是危险的。例如,在这上面使用 memcpy 将是一场灾难。(用 clang 和 g++ 编译)

关于c++ - 替换不可复制、不可移动的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25605793/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com