Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 防止复制返回的引用_C++_C++11 - Fatal编程技术网

C++ 防止复制返回的引用

C++ 防止复制返回的引用,c++,c++11,C++,C++11,我有一个班级管理一些资源。您可以从这个管理类中获得对其中一个资源的引用。资源是很重的对象,所以您通常不想复制它们。在我的例子中,资源的基类不是解决方案,因为我的“资源管理器”是一个模板类,它应该与其他人已经定义的资源类一起工作。我举了一些简单的例子来说明我的问题: #include <iostream> // copyable class class Copyable { public: Copyable() = default; Copyable(const Copyab

我有一个班级管理一些资源。您可以从这个管理类中获得对其中一个资源的引用。资源是很重的对象,所以您通常不想复制它们。在我的例子中,资源的基类不是解决方案,因为我的“资源管理器”是一个模板类,它应该与其他人已经定义的资源类一起工作。我举了一些简单的例子来说明我的问题:

#include <iostream>

// copyable class
class Copyable {
public:
  Copyable() = default;
  Copyable(const Copyable&) {
      std::cout << "Copyconstructor called" << std::endl;
  }

  Copyable& operator=(const Copyable&) {
      std::cout << "assignment operator called" << std::endl;
      return *this;
  }
};

// non copyable class
class NonCopyable {
public:
  NonCopyable() = default;
private:
  NonCopyable(const NonCopyable&) = delete;
  NonCopyable& operator=(const NonCopyable&) = delete;
};

// some class that can return a reference
template <typename T>
class SomeHolder {
private:
    T some_member;
public:    
    T& getReference() {
        return some_member;
    }
};

int main() {
    SomeHolder<Copyable> holder_1;
    auto copyable_1 = holder_1.getReference();    
    auto &copyable_2 = holder_1.getReference();

    SomeHolder<NonCopyable> holder_2;
    //auto noncopyable_1 = holder_2.getReference(); // line 39
    auto &noncopyable_2 = holder_2.getReference();  // line 40
}
#包括
//可复制类
类可复制{
公众:
Copyable()=默认值;
可复制(常量可复制&){

std::cout如果你让你的对象可复制,你肯定没有办法阻止他们复制它

如果您返回对可复制对象的引用,您无法阻止使用您的类的开发人员在某个时候复制它们。如果他们使用
auto&
,则不会复制该对象,但如果他们使用̀
auto
,则会复制该对象……即使他们在调用您的
getReference()时使用了
auto&
function,您无法阻止他们稍后进行复制(当他们调用函数或分配新变量时)

另一种选择,正如“苹果”评论的那样,是返回一个
共享的\u ptr
。然后,您的资源管理器存储指向资源的共享指针并授予对它们的访问权限。然后,调用者可能会使用
共享的\u ptr
的多个实例,所有实例都指向最后未复制的同一个资源。如果他使用
自动
,他将获得一份
共享的\u ptr
,我将如果他使用
auto&
,他会得到一个对
shared\u ptr
的引用,但在这两种情况下,它们都指向未复制的相同资源


如果调用者真的想复制,他会找到一种方法,使用
shared\u ptr::get()
访问可复制对象。

如果你让对象可复制,你肯定没有办法阻止他们复制

如果您返回对可复制对象的引用,您无法阻止使用您的类的开发人员在某个时候复制它们。如果他们使用
auto&
,则不会复制该对象,但如果他们使用̀
auto
,则会复制该对象……即使他们在调用您的
getReference()时使用了
auto&
function,您无法阻止他们稍后进行复制(当他们调用函数或分配新变量时)

另一种选择,正如“苹果”评论的那样,是返回一个
共享的\u ptr
。然后,您的资源管理器存储指向资源的共享指针并授予对它们的访问权限。然后,调用者可能会使用
共享的\u ptr
的多个实例,所有实例都指向最后未复制的同一个资源。如果他使用
自动
,他将获得一份
共享的\u ptr
,我将如果他使用
auto&
,他会得到一个对
shared\u ptr
的引用,但在这两种情况下,它们都指向未复制的相同资源


如果调用者真的想复制,他会通过使用
shared\u ptr::get()找到复制的方法
访问可复制对象。

您不能阻止其他代码复制可复制的对象。因此,如果您希望其他代码无法复制您持有的可复制对象,则不能返回对它们的引用

相反,您可以返回一个包装器对象,该对象将其功能委托给可复制类的一个实例,该类的引用在包装器中私自保存:

template <typename T>
class Wrapper {
    T& t;
public:
    Wrapper(T& t) : t(t) {}
    T* operator->() { return &t; }
};

Wrapper<T> SomeHolder<T>::getSomeMember() {
    return {some_member};
}
模板
类包装器{
T&T;
公众:
包装器(T&T):T(T){}
T*运算符->(){return&T;}
};
包装器SomeHolder::getSomeMember(){
返回{some_member};
}

由于无法重载直接成员访问运算符,您将需要更改调用代码以使用间接成员访问。

您无法阻止其他代码复制可复制的对象。因此,如果您希望其他代码无法复制您持有的可复制对象,则您不能返回对这些对象的引用

相反,您可以返回一个包装器对象,该对象将其功能委托给可复制类的一个实例,该类的引用在包装器中私自保存:

template <typename T>
class Wrapper {
    T& t;
public:
    Wrapper(T& t) : t(t) {}
    T* operator->() { return &t; }
};

Wrapper<T> SomeHolder<T>::getSomeMember() {
    return {some_member};
}
模板
类包装器{
T&T;
公众:
包装器(T&T):T(T){}
T*运算符->(){return&T;}
};
包装器SomeHolder::getSomeMember(){
返回{some_member};
}

由于无法重载直接成员访问运算符,您需要更改调用代码以使用间接成员访问。

我也建议使用智能指针,但我不希望使用引用成员。这样客户端就可以保留句柄

template<typename T>
struct ViewPtr {
  ViewPtr() = delete;
  ViewPtr(T* tp) : tp(tp) {}
  T* operator->() { return tp; }
  const T* operator->() const { return tp; }
  private:
  T* tp;
};
模板
结构视图{
ViewPtr()=删除;
ViewPtr(T*tp):tp(tp){}
T*运算符->(){return tp;}
常量T*运算符->()常量{return tp;}
私人:
T*tp;
};
用法:

template <typename T>
class SomeHolder {
private:
  T some_member;
public:
  ViewPtr<T> getReference() {
    return &some_member;
  }
};
模板
类持有人{
私人:
T一些成员;
公众:
ViewPtr getReference(){
返回&some_成员;
}
};

这个
Viewtr
也选择“传播常量”。也就是说:如果你有一个常量视图对象(或者如果它是一个成员,并且你在一个常量方法中),你会得到一个常量接口。

我也建议使用智能指针,但我不喜欢使用引用成员。这样客户端就可以保留句柄

template<typename T>
struct ViewPtr {
  ViewPtr() = delete;
  ViewPtr(T* tp) : tp(tp) {}
  T* operator->() { return tp; }
  const T* operator->() const { return tp; }
  private:
  T* tp;
};
模板
结构视图{
ViewPtr()=删除;
ViewPtr(T*tp):tp(tp){}
T*运算符->(){return tp;}
常量T*运算符->()常量{return tp;}
私人:
T*tp;
};
用法:

template <typename T>
class SomeHolder {
private:
  T some_member;
public:
  ViewPtr<T> getReference() {
    return &some_member;
  }
};
模板
类持有人{
私人:
T一些成员;
公众:
ViewPtr getReference(){
返回&some_成员;
}
};

这个
Viewtr
也选择“传播常量”。也就是说:如果您有一个常量视图对象(或者如果它是一个成员,并且您使用的是一个常量方法),那么您将得到一个常量接口。

行不是数字。不清楚哪些行是39和40。如果您想停止