Assignment Makes Pointer From Integer Without A Cast Fopen Man

template<

    class T,
    class Deleter =std::default_delete<T>

>class unique_ptr;
(1) (since C++11)
template<

    class T,
    class Deleter

>class unique_ptr<T[], Deleter>;
(2) (since C++11)

is a smart pointer that owns and manages another object through a pointer and disposes of that object when the goes out of scope.

The object is disposed of using the associated deleter when either of the following happens:

  • the managing object is destroyed
  • the managing object is assigned another pointer via operator= or reset().

The object is disposed of using a potentially user-supplied deleter by calling get_deleter()(ptr). The default deleter uses the delete operator, which destroys the object and deallocates the memory.

A may alternatively own no object, in which case it is called empty.

There are two versions of :

1) Manages a single object (e.g. allocated with new)

2) Manages a dynamically-allocated array of objects (e.g. allocated with new[])

The class satisfies the requirements of and , but not the requirements of either or .

Type requirements
- must be or lvalue reference to a or lvalue reference to function, callable with an argument of type

[edit]Notes

Only non-const can transfer the ownership of the managed object to another . If an object's lifetime is managed by a const std::unique_ptr, it is limited to the scope in which the pointer was created.

is commonly used to manage the lifetime of objects, including:

  • providing exception safety to classes and functions that handle objects with dynamic lifetime, by guaranteeing deletion on both normal exit and exit through exception
  • passing ownership of uniquely-owned objects with dynamic lifetime into functions
  • acquiring ownership of uniquely-owned objects with dynamic lifetime from functions
  • as the element type in move-aware containers, such as std::vector, which hold pointers to dynamically-allocated objects (e.g. if polymorphic behavior is desired)

may be constructed for an incomplete type, such as to facilitate the use as a handle in the pImpl idiom. If the default deleter is used, must be complete at the point in code where the deleter is invoked, which happens in the destructor, move assignment operator, and member function of . (Conversely, std::shared_ptr can't be constructed from a raw pointer to incomplete type, but can be destroyed where is incomplete). Note that if is a class template specialization, use of as an operand, e.g. !p requires 's parameters to be complete due to ADL.

If is a derived class of some base , then std::unique_ptr<T> is implicitly convertible to std::unique_ptr<B>. The default deleter of the resulting std::unique_ptr<B> will use operator delete for , leading to undefined behavior unless the destructor of is virtual. Note that std::shared_ptr behaves differently: std::shared_ptr<B> will use the operator delete for the type and the owned object will be deleted correctly even if the destructor of is not virtual.

Unlike std::shared_ptr, may manage an object through any custom handle type that satisfies . This allows, for example, managing objects located in shared memory, by supplying a that defines or another fancy pointer.

[edit]Member types

Member type Definition
pointerstd::remove_reference<Deleter>::type::pointer if that type exists, otherwise . Must satisfy
element_type, the type of the object managed by this
deleter_type, the function object or lvalue reference to function or to function object, to be called from the destructor

[edit]Member functions

[edit]Non-member functions

[edit]Helper classes

[edit]Example

Run this code

Output:

#include <iostream>#include <vector>#include <memory>#include <cstdio>#include <fstream>#include <cassert>#include <functional>   struct B {virtualvoid bar(){std::cout<<"B::bar\n";}virtual ~B()=default;};struct D : B { D(){std::cout<<"D::D\n";} ~D(){std::cout<<"D::~D\n";}void bar() override {std::cout<<"D::bar\n";}};   // a function consuming a unique_ptr can take it by value or by rvalue reference std::unique_ptr<D> pass_through(std::unique_ptr<D> p){ p->bar();return p;}   int main(){std::cout<<"unique ownership semantics demo\n";{auto p =std::make_unique<D>();// p is a unique_ptr that owns a Dauto q = pass_through(std::move(p));assert(!p);// now p owns nothing and holds a null pointer q->bar();// and q owns the D object}// ~D called here   std::cout<<"Runtime polymorphism demo\n";{ std::unique_ptr<B> p =std::make_unique<D>();// p is a unique_ptr that owns a D// as a pointer to base p->bar();// virtual dispatch   std::vector<std::unique_ptr<B>> v;// unique_ptr can be stored in a container v.push_back(std::make_unique<D>()); v.push_back(std::move(p)); v.emplace_back(new D);for(auto& p: v) p->bar();// virtual dispatch}// ~D called 3 times   std::cout<<"Custom deleter demo\n";std::ofstream("demo.txt")<<'x';// prepare the file to read{ std::unique_ptr<std::FILE, decltype(&std::fclose)> fp(std::fopen("demo.txt", "r"), &std::fclose);if(fp)// fopen could have failed; in which case fp holds a null pointerstd::cout<<(char)std::fgetc(fp.get())<<'\n';}// fclose() called here, but only if FILE* is not a null pointer// (that is, if fopen succeeded)   std::cout<<"Custom lambda-expression deleter demo\n";{ std::unique_ptr<D, std::function<void(D*)>> p(new D, [](D* ptr){std::cout<<"destroying from a custom deleter...\n"; delete ptr;});// p owns D p->bar();}// the lambda above is called and D is destroyed   std::cout<<"Array form of unique_ptr demo\n";{ std::unique_ptr<D[]> p{new D[3]};}// calls ~D 3 times}
unique ownership semantics demo D::D D::bar D::bar D::~D Runtime polymorphism demo D::D D::bar D::D D::D D::bar D::bar D::bar D::~D D::~D D::~D Custom deleter demo x Custom lambda-expression deleter demo D::D D::bar destroying from a custom deleter... D::~D Array form of unique_ptr demo D::D D::D D::D D::~D D::~D D::~D

使用第三方库的时候,很可能遇到这样的问题,我们需要处理某个文件,而这个文件不一定是从本地磁盘上读取,可能是分布式文件系统或者其他地方,而第三方库的接口却只提供了一个参数,意味着只能从磁盘加载,没法直接处理已经加载到内存的数据。

这个时候,fmemopen就可以派上用场了,完美的将FILE对象映射到内存上,无需从磁盘上读取了。fmemopen的函数签名很简单,如下:

需要注意的是,在使用前最好仔细的阅读 man fmemopen的内容,尤其是在wa两种模式下,函数的行为。

有两个小问题需要注意下:

  • 在glibc 2.9之前的版本暂不支持模式,这个问题带来的影响是,若以binary模式打开,进行fseek(stream, 0L, SEEK_END)时,pos指针很可能不会到真正的尾,而是buffer中第一个 处。对比glibc 2.5 和glibc 2.21的代码可以知道:

    //glibc 2.21 case SEEK_END: np = (c->binmode ? c->size : c->maxpos) - *p; break;

    //glibc 2.5 case SEEK_END: np = c->maxpos - *p; break;

在非模式下,glib2.5是按maxpos处理的,而maxpos是通过strlen(buffer)得到的,glib 2.21则是c->size,即调用fmemopen时传入的值。

  • 对于在glibc 2.10以下的版本中,使用fmemopen编译时会遇到这样的警告:

    warning: assignment makes pointer from integer without a cast

这个警告的解决方式是在include stdio.h头文件之前添加一行,正如man page上所说。

应用


有了fmemopen之后,譬如我们需要将从已经加载到内存的一个zip文件提取出文件列表,即这个,对于解压zip文件,我目前知道的库是minizip,简单好用,然而,这个minizip中提供的接口都是,通过path调用fopen得到一个FILE的对象,然后在这个FILE对象上封装一系列的操作,这些操作就复杂了,没必要进行深入了解。在fmemopen的协助下,我们可以内存中获取一个FILE对象出来,然后再给minizip使用,轻而易举的解决了这个问题。

0 Thoughts to “Assignment Makes Pointer From Integer Without A Cast Fopen Man

Leave a comment

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati *