如何在不从容器中取得所有权的情况下访问容器的unique_ptr元素(通过迭代器)?当一个人获得容器中元素的迭代器时,元素所有权仍然与容器有关吗?当一个解引用迭代器来获取对unique_ptr的访问权限时怎么样?这是否执行unique_ptr的隐式移动?
当我需要将元素存储在容器中(而不是通过值)时,我发现我正在使用shared_ptr,即使容器在概念上拥有元素而其他代码只是希望操纵容器中的元素,因为我害怕无法实际访问容器中的unique_ptr元素而不从中获取所有权.
任何见解?
我的编译器不支持make_unique.怎么写一个?
template< class T, class... Args > unique_ptr<T> make_unique( Args&&... args );
Run Code Online (Sandbox Code Playgroud) 我试图用来std::make_unique
实现一个构造函数要接收的类std::initializer_list
.这是一个最小的案例:
#include <string>
#include <vector>
#include <initializer_list>
#include <memory>
struct Foo {
Foo(std::initializer_list<std::string> strings) : strings(strings) {}
std::vector<std::string> strings;
};
int main(int, char**) {
auto ptr = std::make_unique<Foo>({"Hello", "World"});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
您可以在Coliru上看到它没有构建:
main.cpp:14:56: error: no matching function for call to 'make_unique(<brace-enclosed initializer list>)'
auto ptr = std::make_unique<Foo>({"Hello", "World"});
Run Code Online (Sandbox Code Playgroud)
那么,make_unique
据说无法使用initializer_list
s?GCC 4.9.1中有错误吗?或者我忽略了什么?
我想声明std::make_unique
函数是我班级的朋友.原因是我想声明我的构造函数protected
并提供一种使用创建对象的替代方法unique_ptr
.这是一个示例代码:
#include <memory>
template <typename T>
class A
{
public:
// Somehow I want to declare make_unique as a friend
friend std::unique_ptr<A<T>> std::make_unique<A<T>>();
static std::unique_ptr<A> CreateA(T x)
{
//return std::unique_ptr<A>(new A(x)); // works
return std::make_unique<A>(x); // doesn't work
}
protected:
A(T x) { (void)x; }
};
int main()
{
std::unique_ptr<A<int>> a = A<int>::CreateA(5);
(void)a;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
现在我收到此错误:
Start
In file included from prog.cc:1:
/usr/local/libcxx-head/include/c++/v1/memory:3152:32: error: calling a protected constructor of class 'A<int>'
return …
Run Code Online (Sandbox Code Playgroud) 先来看看什么C++入门谈到unique_ptr
和shared_ptr
:
$ 16.1.6.效率和灵活性
我们可以确定
shared_ptr
不将删除器作为直接成员,因为删除器的类型直到运行时才知道.因为删除器的类型是a
unique_ptr
类型的一部分,所以删除器成员的类型在编译时是已知的.删除器可以直接存储在每个unique_ptr
对象中.
所以似乎shared_ptr
没有直接的删除成员,但unique_ptr
确实如此.然而,另一个问题的最高投票回答说:
如果将deleter作为模板参数提供(如
unique_ptr
),则它是类型的一部分,您不需要在此类型的对象中存储任何其他内容.如果将deleteter作为构造函数的参数传递(如shared_ptr
),则需要将其存储在对象中.这是额外灵活性的代价,因为您可以为相同类型的对象使用不同的删除器.
引用的两段完全相互矛盾,让我感到困惑.更重要的是,许多人说unique_ptr
是零开销,因为它不需要将删除器存储为成员.但是,正如我们所知,unique_ptr
有一个构造函数unique_ptr<obj,del> p(new obj,fcn)
,这意味着我们可以将删除函数传递给它,因此unique_ptr
似乎已将删除函数存储为成员.真是一团糟!
为什么这不起作用?
#include <map>
#include <memory>
void deleter(int* i) {
delete i;
}
std::map<int, std::unique_ptr<int, decltype(&deleter)>> m;
void foo(int* i) {
m[0] = std::unique_ptr<int, decltype(&deleter)>(i, &deleter);
}
Run Code Online (Sandbox Code Playgroud)
看看难以理解的编译错误https://godbolt.org/z/Uhp9NO.
In file included from <source>:1:
In file included from /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/map:61:
In file included from /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/stl_map.h:63:
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/tuple:1668:9: error: no matching constructor for initialization of 'std::unique_ptr<int, void (*)(int *)>'
second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
^
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/tuple:1655:9: note: in instantiation of function template specialization 'std::pair<const int, std::unique_ptr<int, void (*)(int *)> >::pair<int &&, 0>' requested here
: pair(__first, __second, …
Run Code Online (Sandbox Code Playgroud) unique_ptr线程安全吗?以下代码是否无法两次打印相同的数字?
#include <memory>
#include <string>
#include <thread>
#include <cstdio>
using namespace std;
int main()
{
unique_ptr<int> work;
thread t1([&] {
while (true) {
const unique_ptr<int> localWork = move(work);
if (localWork)
printf("thread1: %d\n", *localWork);
this_thread::yield();
}
});
thread t2([&] {
while (true) {
const unique_ptr<int> localWork = move(work);
if (localWork)
printf("thread2: %d\n", *localWork);
this_thread::yield();
}
});
for (int i = 0; ; i++) {
work.reset(new int(i));
while (work)
this_thread::yield();
}
return 0;
}
Run Code Online (Sandbox Code Playgroud) 在VC2012中,我想使用唯一指针和删除器在构造函数中创建一个互斥锁,这样我就不需要创建一个析构函数来调用CloseHandle.
我原以为这会起作用:
struct foo
{
std::unique_ptr<HANDLE, BOOL(*)(HANDLE)> m_mutex;
foo() : m_mutex(CreateMutex(NULL, FALSE, NULL), CloseHandle) {}
}
Run Code Online (Sandbox Code Playgroud)
但在编译时我收到一个错误:
error C2664: 'std::unique_ptr<_Ty,_Dx>::unique_ptr(void *,int
(__cdecl *const &)(HANDLE)) throw()' : cannot convert parameter 1 from
'HANDLE' to 'void *'
Run Code Online (Sandbox Code Playgroud)
当我修改构造函数时:
foo() : m_mutex((void*)CreateMutex(NULL, FALSE,
(name + " buffer mutex").c_str()), CloseHandle) {}
Run Code Online (Sandbox Code Playgroud)
我变得更加不寻常:
error C2664: 'std::unique_ptr<_Ty,_Dx>::unique_ptr(void *,
int (__cdecl *const &)(HANDLE)) throw()' : cannot convert
parameter 1 from 'void *' to 'void *'
Run Code Online (Sandbox Code Playgroud)
我现在不知所措.HANDLE是void*的typedef:我需要了解一些转换魔法吗?
假设我有一组unique_ptr:
std::unordered_set <std::unique_ptr <MyClass>> my_set;
Run Code Online (Sandbox Code Playgroud)
我不确定检查集合中是否存在给定指针的安全方法是什么.这样做的正常方法可能是调用my_set.find ()
,但我作为参数传递什么?
我从外面得到的只是一个原始指针.所以我必须从指针创建另一个unique_ptr,将它传递给find()
然后release()
指针,否则对象将被破坏(两次).当然,这个过程可以在一个函数中完成,因此调用者可以传递原始指针并进行转换.
这种方法安全吗?有没有更好的方法来使用一组unique_ptr?
为什么make_unique调用编译?make_unqiue不要求其模板参数是完整类型吗?
struct F;
int main()
{
std::make_unique<F>();
}
struct F {};
Run Code Online (Sandbox Code Playgroud)
在从orignated问题我的"问题"与我PIMPL实现:
我确实理解为什么析构函数必须在用户声明并在实现类(PIMPL)的cpp文件中定义.
但是移动包含pimpl的类的构造函数仍会编译.
class Object
{};
class CachedObjectFactory
{
public:
CachedObjectFactory();
~CachedObjectFactory();
std::shared_ptr<Object> create(int id) const;
private:
struct CacheImpl;
std::unique_ptr<CacheImpl> pImpl;
};
Run Code Online (Sandbox Code Playgroud)
现在cpp文件:
// constructor with make_unique on incompete type ?
CachedObjectFactory::CachedObjectFactory()
: pImpl(std::make_unique<CacheImpl>())
{}
struct CachedObjectFactory::CacheImpl
{
std::map<int, std::shared_ptr<Object>> idToObjects;
};
//deferred destructor
CachedObjectFactory::~CachedObjectFactory() = default;
Run Code Online (Sandbox Code Playgroud)
有人可以解释为什么这个编译?为什么建筑和破坏之间存在差异?如果析构函数的实例化和default_deleter的实例化是一个问题,为什么make_unique的实例化不是问题?
c++ ×10
unique-ptr ×10
c++11 ×5
c++14 ×3
templates ×2
containers ×1
iterator ×1
pimpl-idiom ×1
stl ×1
winapi ×1