C ++返回无法复制的临时值和对象

时间:2014-02-04 22:37:28

标签: c++ reference return-value

我知道C ++中的引用可以extend the lifetime of a return value。有了这个哲学,我尝试了以下内容:我有三个分支,'张量','视图'和'mutable_view'。张量上的Operator()返回“const视图”对象。此视图具有私有拷贝构造函数,因此无法复制视图,因为它保留有关可能无法在当前语句之外生存的张量的信息。

#include <iostream>
#include <algorithm>

struct tensor {

  int data[10];

  class view {
    const int *const data;

    view();
    view(const view &);
  public:
    view(const int *new_data) : data(new_data) {}
    int operator*() const { return *data; }
  };

  class mutable_view {
    int *const data;

    mutable_view();
    mutable_view(const mutable_view &);
  public:
    mutable_view(int *new_data) : data(new_data) {}

    void operator=(const view &v) {
      *data = *v;
    }
  };

  tensor(int n) {
    std::fill(data, data+10, n);
  }

  const view operator()(int ndx) const {
    return view(data + ndx);
  }

  mutable_view at(int ndx) {
    return mutable_view(data + ndx);
  }
};


int main()
{

  tensor a(1);
  tensor b(2);

  b.at(2) = a(2);

  for (int i = 0; i < 10; i++)
    std::cout << "a[i] = " << b.data[i] << std::endl;

  for (int i = 0; i < 10; i++)
    std::cout << "b[i] = " << b.data[i] << std::endl;

  exit(0);
}

问题在于,虽然此代码在gcc中工作(取决于版本),但icc表示警告,而open64根本不构建它:它要求来自“view”的构造函数是公共的。阅读icc的消息,想法似乎是编译器可能会复制右手值,因此需要构造函数。

这是真的吗?是否有一种解决方法可以保留我想要构建的语法?顺便说一下,为了避免基于shared_ptr或其他东西的低效实现,我需要保持“视图”对象不可复制。

修改1:

张量无法控制视图的生命周期。视图由访问者创建,其生命周期仅限于使用它们的语句,原因如下:

  • 这些视图仅用于两件事:(i)复制数据,(ii)提取张量的部分。
  • 张量是实现写时复制语义的多维数组,这意味着视图不能是长期存在的对象:如果数据发生变化,它们就会过期。

编辑2:

更改了伪代码描述(伙伴们,如果你看到'...'你希望它可以编译吗?),那个建立在'icc'而不是在clang / open64上

2 个答案:

答案 0 :(得分:2)

继续,让默认的副本构造函数公开。并记录viewmutable_view在其tensor被更改或销毁时“无效”。

这类似于标准库如何处理具有依赖于另一个对象的生命周期的迭代器,指针和引用。

答案 1 :(得分:0)

正如其他人已经指出你错过了():

const view operator(int ndx) const;

无论如何,这个声明意味着复制了返回值。如果您想避免复制,只需返回对象的引用:

const view& operator()(int ndx) const;

据我所知,'tensor'是'views'的容器,所以它管理那里的生命周期以及返回引用的安全性。出于同样的原因,tensor :: at应该返回对mutable_view的引用:

mutable_view& at(int ndx);

另一个问题是关于'view'的默认构造函数 - 看起来'tensor'必须是'view'的朋友才能创建它的实例

顺便说一下 - 更喜欢使用'size_t'作为索引类型而不是'int'

我对此代码的整体感觉 - 您正在尝试实现一种域语言。也许最好专注于具体的计算任务?