当前位置:  开发笔记 > 编程语言 > 正文

标准是否表明副本必须等效?

如何解决《标准是否表明副本必须等效?》经验,为你挑选了1个好方法。

假设我有一个奇怪的字符串类型,拥有或不拥有它的底层缓冲区:

class WeirdString {
private:
    char* buffer;
    size_t length;
    size_t capacity;
    bool owns;

public:
    // Non-owning constructor
    WeirdString(char* buffer, size_t length, size_t capacity)
        : buffer(buffer), length(length), capacity(capacity), owns(false)
    { }

    // Make an owning copy
    WeirdString(WeirdString const& rhs)
        : buffer(new char[rhs.capacity])
        , length(rhs.length)
        , capacity(rhs.capacity)
        , owns(true)
    {
        memcpy(buffer, rhs.buffer, length);
    }

    ~WeirdString() {
        if (owns) delete [] buffer;
    }
};

复制构造函数是否违反了某个标准?考虑:

WeirdString get(); // this returns non-owning string
const auto s = WeirdString(get());

s是拥有还是非拥有,具体取决于附加的复制构造函数是否被省略,在C++ 14及更早版本中是允许的但是可选的(尽管在C++ 17中是有保证的).Schrödinger的所有权模型表明这个拷贝构造函数本身就是未定义的行为.

是吗?


一个更具说明性的例子可能是:

struct X {
    int i;

    X(int i)
      : i(i)
    { }

    X(X const& rhs)
      : i(rhs.i + 1)
    { }        ~~~~
};

X getX();
const auto x = X(getX());

取决于哪些副本被删除,x.i可能比返回的任何内容多0,1或2 getX().标准是否对此有所说明?



1> Cheers and h..:

关于新问题的代码

struct X {
    int i;

    X(int i)
      : i(i)
    { }

    X(X const& rhs)
      : i(rhs.i + 1)
    { }        ~~~~
};

X getX();
const auto x = X(getX());

这里复制构造函数不会复制,所以你打破了编译器的假设.

使用C++ 17,我相信你可以保证在上面的例子中没有调用它.但是我手头没有C++ 17的草稿.

对于C++ 14及更早版本,由编译器决定是否为调用调用复制构造函数getX,以及是否为复制初始化调用它.

C++14§12.8/ 31 class.copy/31:

"当满足某些条件时,允许实现省略类对象的复制/移动构造,即使为复制/移动操作选择的构造函数和/或对象的析构函数具有副作用.

从术语的形式意义来看,这不是未定义的行为,它可以调用鼻子恶魔.对于正式术语,我会选择未指定的行为,因为这种行为取决于实现而不需要记录.但正如我所知,人们选择的名称并不重要:重要的是标准只是说在规定条件下编译器可以优化复制/移动构造,而不管优化离开构造函数的副作用 - 因此,你不能也不应该依赖.

推荐阅读
夏晶阳--艺术
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有