我编写了一个静态工厂方法,它返回从另一个数据对象填充的新Foobar对象.我最近一直沉迷于所有权语义,我想知道我是否通过这种工厂方法返回一个正确的信息unique_ptr
.
class Foobar {
public:
static unique_ptr<Foobar> factory(DataObject data);
}
Run Code Online (Sandbox Code Playgroud)
我的目的是告诉客户端代码他们拥有指针.没有智能指针,我只会回来Foobar*
.但是,我想强制删除这个内存以避免潜在的错误,所以这unique_ptr
似乎是一个合适的解决方案.如果客户端想要延长指针的生命周期,他们只需在调用.release()
后调用unique_ptr
.
Foobar* myFoo = Foobar::factory(data).release();
Run Code Online (Sandbox Code Playgroud)
我的问题分为两部分:
unique_ptr
而不是原始指针这是一个"坏习惯" 吗?正如Boost中的情况一样,C++ 11提供了一些用于转换的函数shared_ptr
:
std::static_pointer_cast
std::dynamic_pointer_cast
std::const_pointer_cast
Run Code Online (Sandbox Code Playgroud)
但是,我想知道为什么没有等效功能unique_ptr
.
考虑以下简单示例:
class A { virtual ~A(); ... }
class B : public A { ... }
unique_ptr<A> pA(new B(...));
unique_ptr<A> qA = std::move(pA); // This is legal since there is no casting
unique_ptr<B> pB = std::move(pA); // This is not legal
// I would like to do something like:
// (Of course, it is not valid, but that would be the idea)
unique_ptr<B> pB = std::move(std::dynamic_pointer_cast<B>(pA));
Run Code Online (Sandbox Code Playgroud)
是否有任何理由不鼓励这种使用模式,因此,shared_ptr
没有提供与现有模式相同的功能unique_ptr …
我想它是非常自我解释的 - 我似乎无法使用C++ 11的功能,即使我认为我已经正确设置了所有东西 - 这可能意味着我没有.
这是我的代码:
#include <cstdlib>
#include <iostream>
class Object {
private:
int value;
public:
Object(int val) {
value = val;
}
int get_val() {
return value;
}
void set_val(int val) {
value = val;
}
};
int main() {
Object *obj = new Object(3);
std::unique_ptr<Object> smart_obj(new Object(5));
std::cout << obj->get_val() << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是我的g ++版本:
ubuntu@ubuntu:~/Desktop$ g++ --version
g++ (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04) 4.7.3
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see …
Run Code Online (Sandbox Code Playgroud) 我正试图"现代化"一些现有的代码.
这很好用,但为了"现代化"我的代码,我认为我应该更改要定义的变量,"std::unique_ptr<Device> device_"
并删除显式调用delete,这使得代码更安全,通常更好.
我的问题是这个 -
我可以调用.get来获取每个函数调用中的原始指针.但这看起来很丑陋,浪费了一些首先使用unique_ptr的原因.
或者我可以更改每个函数,以便不使用"Device*"类型的参数,而是使用"std :: unique_ptr&"类型的参数.哪个(对我来说)有点模糊了函数原型,并使它们难以阅读.
这是什么最佳做法?我错过了其他选择吗?
我有以下一批代码:
std::vector<std::unique_ptr<AVLTree_GeeksforGeeks>> AVLArray(100000);
/* Let's add some objects in the vector */
AVLTree_GeeksforGeeks *avl = new AVLTree_GeeksforGeeks();
avl->Insert[2]; avl->Insert[5]; AVL->Insert[0];
unique_ptr<AVLTree_GeeksforGeeks> unique_p(avl);
AVLArray[0] = move(unique_p);
/* we do this for a number of other trees, let's say another 9...
...
...
Now the vector has objects up until AVLTree[9] */
/* Let's try iterating through its valid, filled positions */
for(auto i : AVLTree )
{
cout << "Hey there!\n"; //This loop should print 10 "Hey there"s.
}
Run Code Online (Sandbox Code Playgroud)
茹罗.最后一部分,for()循环中的编译错误. …
我对unique_ptr和rvalue move哲学很困惑.
假设我们有两个集合:
std::vector<std::auto_ptr<int>> autoCollection;
std::vector<std::unique_ptr<int>> uniqueCollection;
Run Code Online (Sandbox Code Playgroud)
现在我希望以下内容失败,因为没有人知道算法在内部做了什么,也许还在制作内部数据透视副本等,从而剥夺了auto_ptr的所有权:
std::sort(autoCollection.begin(), autoCollection.end());
Run Code Online (Sandbox Code Playgroud)
我明白了 并且编译器正确地不允许这种情况发生.
但后来我这样做:
std::sort(uniqueCollection.begin(), uniqueCollection.end());
Run Code Online (Sandbox Code Playgroud)
这编译.我不明白为什么.我不认为unique_ptrs可以复制.这是否意味着不能采用枢轴值,因此排序效率较低?或者这个转轴实际上是一个移动,实际上和auto_ptrs的集合一样危险,编译器应该不允许这样做?
我想我错过了一些重要的信息,所以我急切等待有人给我提供啊哈!时刻.
std::unique_ptr<int> p1(new int);
std::unique_ptr<int> p2(new int);
p2=p1;
Run Code Online (Sandbox Code Playgroud)
在这里似乎p1不再是"唯一的",因为p2也指它
这是合法的c ++?unique_ptr有copy_semantics吗?如果不是,并且它只有移动语义,那么在将p1分配给p2后p1是否设置为NULL?
编辑:
好的,所以正确的版本是
p2=std::move(p1)
Run Code Online (Sandbox Code Playgroud)
据此,在此分配后,p1无效?与auto_ptr的区别在哪里?所有权明确规定所有权转让比隐式更安全,因为我认为auto_ptr是这种情况
假设我有处理基类和派生类的工厂函数:
#include <memory>
using namespace std;
struct B { virtual ~B() {} };
struct D : B {};
unique_ptr<B> MakeB()
{
auto b = unique_ptr<B>( new B() );
return b; // Ok!
}
unique_ptr<B> MakeD()
{
auto d = unique_ptr<D>( new D() );
return d; // Doh!
}
Run Code Online (Sandbox Code Playgroud)
在上面的最后一行,我需要move(d)
为了使它工作,否则我得到"错误:无效转换std::unique_ptr<D>
为std::unique_ptr<D>&&
." 我的直觉说,在这种情况下,编译器应该知道它可以隐式地创建d
一个rvalue并将其移动到基指针中,但事实并非如此.
这在我的编译器(gcc 4.8.1和VS2012)中是不可靠的吗?预期的设计unique_ptr
?标准有缺陷吗?
我正在阅读"Effective Modern C++".在与std::unique_ptr
它相关的项目中声明如果自定义删除器是无状态对象,则不会出现大小费用,但如果它是函数指针或std::function
大小费用发生.你能解释一下原因吗?
假设我们有以下代码:
auto deleter_ = [](int *p) { doSth(p); delete p; };
std::unique_ptr<int, decltype(deleter_)> up(new int, deleter_);
Run Code Online (Sandbox Code Playgroud)
根据我的理解,unique_ptr
应该有一个类型的对象decltype(deleter_)
并分配deleter_
给该内部对象.但显然这不是正在发生的事情.你能用最小的代码示例来解释这背后的机制吗?
我经常发现自己想写这样的代码:
class MyClass
{
public:
void addObject(std::unique_ptr<Object>&& newObject);
void removeObject(const Object* target);
private:
std::set<std::unique_ptr<Object>> objects;
};
Run Code Online (Sandbox Code Playgroud)
但是,很多std :: set接口对std :: unique_ptrs都没用,因为查找函数需要std :: unique_ptr参数(我显然没有这些参数,因为它们由集合本身拥有).
我可以想到两个主要的解决方案.
创建临时unique_ptr以进行查找.例如,上面的removeObject()可以实现如下:
void MyClass::removeObject(const Object* target)
{
std::unique_ptr<Object> targetSmartPtr(target);
objects.erase(targetSmartPtr);
targetSmartPtr.release();
}
Run Code Online (Sandbox Code Playgroud)将原始指针映射替换为unique_ptrs.
// ...
std::map<const Object*, std::unique_ptr<Object>> objects;
};
Run Code Online (Sandbox Code Playgroud)然而,对我来说,两者似乎都有点愚蠢.在解决方案1中,erase()不是noexcept,因此临时unique_ptr可能会删除它实际上不拥有的对象,而2需要不必要地为容器存储两倍.
我知道Boost的指针容器,但与现代C++ 11标准库容器相比,它们目前的功能有限.
我最近在阅读有关C++ 14的内容,并且遇到了"将异构比较查找添加到关联容器".但是形成我对它的理解,查找类型必须与键类型相当,但原始指针不能与unique_ptrs相比.
任何人都知道更优雅的解决方案或即将添加的C++解决了这个问题?