Manually increase and decrease boost :: shared_ptr?

Is there a way to manually increase and decrease the number of shared_ptr in C ++?

The problem I'm trying to solve is the following. I am writing a library in C ++, but the interface should be in pure C. Inside, I would like to use shared_ptr to simplify memory management, while maintaining the ability to pass a raw pointer through the C interface.

When I pass the raw pointer through the interface, I would like to increase the reference count. The client will then be responsible for calling a function that will decrease the reference count when it no longer needs the passed object.

+5
source share
7 answers

In your offer

.

, , , . , .

shared_ptr... (, , ...), .

1:

(shared_ptr:: release) , ( , ).

, . , shared_ptr . , ... .

2:

, ( ) , . , , , .

struct Object;

class Pool // may be a singleton, may be synchronized for multi-thread usage
{
public:
  int accept(boost::shared_ptr<Object>); // adds ptr to the map, returns NEW id
  void release(int id) { m_objects.erase(id); }

private:
  std::map< int, boost::shared_ptr<Object> > m_objects;
}; // class Pool

, "" , , shared_ptr:)

:: shared_ptr

, ( ++), shared_ptr. .

( ) - (my_shared_ptr?), :

  • shared_ptr
  • shared_ptr ( )
  • , , .

, shared_ptr, . , C , , , "" , ( , ).

"reinterpret_cast", . - C/++!

? , , .

+7

, boost:: shared_ptr DLL, . boost:: intrusive_ptr . shared_ptr, ... , , , , -)

ADDED 07/2010: , , / DLL, shared_ptr. , boost::intrusive_ptr shared_ptr. .NET- TR1 , , ...

+10

1. ?

, , . , free .

, .

2. ?

, Matthieu M. , , / .

C, , delete - . , :

#ifndef MY_STRUCT_H
#define MY_STRUCT_H

#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus

typedef struct MyStructDef{} MyStruct ; // dummy declaration, to help
                                        // the compiler not mix types

MyStruct * MyStruct_new() ;
size_t     MyStruct_getSomeValue(MyStruct * p) ;
void       MyStruct_delete(MyStruct * p) ;

#ifdef __cplusplus
}
#endif // __cplusplus

#endif // MY_STRUCT_H

. , C, void *. void * - .

++, , :

#include "MyClass.hpp"
#include "MyStruct.h"

MyManager g_oManager ; // object managing the shared instances
                       // of your class

extern "C"
{

MyStruct * MyStruct_new()
{
   MyClass * pMyClass = g_oManager.createMyClass() ;
   MyStruct * pMyStruct = reinterpret_cast<MyStruct *>(pMyClass) ;
   return pMyStruct ;
}

size_t MyStruct_getSomeValue(MyStruct * p)
{
   MyClass * pMyClass = reinterpret_cast<MyClass *>(p) ;

   if(g_oManager.isMyClassExisting(pMyClass))
   {
      return pMyClass->getSomeValue() ;
   }
   else
   {
      // Oops... the user made a mistake
      // Handle it the way you want...
   }

   return 0 ;
}

void MyStruct_delete(MyStruct * p)
{
   MyClass * pMyClass = reinterpret_cast<MyClass *>(p) ;
   g_oManager.destroyMyClass(pMyClass) ;
}

}

, MyStruct . - reinterpret_cast-ing-it MyClass (. Jaif answer . C MyStruct_ *.

, , . , (. )

3.

, ., , ( , , ). multimap, - .

, , ++ , "" ( /, __FILE__ __LINE__ ).

, :

  • ( C , ?)
  • , .
  • , ( RAII) , .
  • , ,
+3

: , ( ). , . DLL-, .

+2

, - , IOCompletionPorts concurrency. , , , Herb Sutter .

std:: shared_ptr, VC11:

Impl:

namespace {
    struct HackClass {
        std::_Ref_count_base *_extracted;
    };
}

template<>
template<>
void std::_Ptr_base<[YourType]>::_Reset<HackClass>(std::auto_ptr<HackClass> &&h) {
     h->_extracted = _Rep; // Reference counter pointer
}

std::_Ref_count_base *get_ref_counter(const std::shared_ptr<[YourType]> &p) {
     HackClass hck;
     std::auto_ptr<HackClass> aHck(&hck);

     const_cast<std::shared_ptr<[YourType]>&>(p)._Reset(std::move(aHck));

     auto ret = hck._extracted; // The ref counter for the shared pointer
                                // passed in to the function

     aHck.release(); // We don't want the auto_ptr to call delete because
                     // the pointer that it is owning was initialized on the stack

     return ret;
}

void increment_shared_count(std::shared_ptr<[YourType]> &sp) {
     get_ref_counter(sp)->_Incref();
}

void decrement_shared_count(std::shared_ptr<[YourType]> &sp) {
     get_ref_counter(sp)->_Decref();
}

[YourType] , . , , , . , , , , , . , auto_ptr, , shared_ptr, auto_ptr.

+1

shared_ptr, , . , C api.

increment() decment() shared_ptr. shared_ptr .

#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/scoped_ptr.hpp>
using namespace std;

typedef boost::shared_ptr<int> MySharedPtr;
MySharedPtr ptr = boost::make_shared<int>(123);

void* increment()
{
    // copy constructor called
    return new MySharedPtr(ptr);
}

void decrement( void* x)
{
    boost::scoped_ptr< MySharedPtr > myPtr( reinterpret_cast< MySharedPtr* >(x) );
}

int main()
{
    cout << ptr.use_count() << endl;
    void* x = increment();
    cout << ptr.use_count() << endl;
    decrement(x);
    cout << ptr.use_count() << endl;

    return 0;
}

:

1
2
1

+1

( , ).

template< class T >
class shared_pool
{
public:

    typedef T value_type;
    typedef shared_ptr< value_type > value_ptr;
    typedef value_ptr* lock_handle;

shared_pool( size_t maxSize ):
    _poolStore( maxSize )
{}

// returns nullptr if there is no place in vector, which cannot be resized without locking due to concurrency
lock_handle try_acquire( const value_ptr& lockPtr ) {
    static value_ptr nullPtr( nullptr );
    for( auto& poolItem: _poolStore ) {
        if( std::atomic_compare_exchange_strong( &poolItem, &nullPtr, lockPtr ) ) {             
            return &poolItem;
        }
    }
    return nullptr;
}


lock_handle acquire( const value_ptr& lockPtr ) {
    lock_handle outID;
    while( ( outID = try_acquire( lockPtr ) ) == nullptr ) {
        mt::sheduler::yield_passive(); // ::SleepEx( 1, false );
    }
    return outID;
}

value_ptr release( const lock_handle& lockID ) {
    value_ptr lockPtr( nullptr );
    std::swap( *lockID, lockPtr);
    return lockPtr;
}

protected:

    vector< value_ptr > _poolStore;

};

std:: map , , , . .

By the way, hacking with manual release / acquisition seems to be a much better approach (in terms of speed and memory usage). C ++ std is better to add this functionality to its classes, just to save the C ++ shaving form.

0
source

All Articles