0

if we have a code like this :

void g(int *n){
int m=n[1];    
n= null ;  
}  
void main(){  
int ∗ p = (int∗)malloc(10 ∗ sizeof (int));  
int * q= p;  
g(p);  
}   

so we know if we overload malloc, calloc , realloc ,new ,free and delete functions we can track first pointer that create or delete with this functions(p pointer in above example ) but how can i find and track other pointers and functions that using this allocated memory ? ( q pointer and g function in above example ) .should i overload Assignment statement and function call ? if yes how ? in other words i want to know live objects and last used time and location of an allocated memory too . i want to implement an custom memory leak detection tools so i need to find all objects and pointer that using an allocated memory before report it that's leak or not .

1 Answers1

0

What you're talking about is called reference counting. Searching stackoverflow for this topic gives you these results:

  1. What is a smart pointer and when should I use one?
  2. How does a reference-counting smart pointer's reference counting work?
  3. what exactly reference counting in c++ means?,

The standard template library already has a std::shared_ptr which does that.

We need to keep track of the lifecycle of the resource, this is possible by controlling the creation, the copying and the deletion. If you do it without using a class, you'll end up with some functions, a state variable and a global variable. This is not very effective in keeping the concept of the shared resource in the focus of the user's mind. One tends to forget that one is using a shared resource because one sees a naked pointer and tends to use it like one, which would disregard the provided shared-pointer functionality.

If you were to encapsulate the functionality in a class, you should want to implement the concept for all types i.e. you should want to use templates. one way would be this:

#include <vector>
#include <stdexcept>
#include <cstdlib>

#ifndef SHARED_PTR_H
#define SHARED_PTR_H

template<class Tres_t>
class shared_pointer
{
    // members
    
    Tres_t* data_;
    static std::vector<std::size_t> ref_counts_;
    std::size_t ref_index_ = {};
    
public:
    
    // lifecycle
    
    shared_pointer() = delete;
    
    shared_pointer(const std::size_t& size)
        : data_{nullptr}
    {
        data_ = static_cast<Tres_t*>(std::malloc(size * sizeof(Tres_t)));
        ref_counts_.push_back(1);
        ref_index_ = ref_counts_.size() - 1;
    }
    
    shared_pointer(const shared_pointer& rhs)
        : data_{rhs.data_}, ref_index_{rhs.ref_index_}
    {
        if (ref_index_ >= ref_counts_.size())
        {
            throw std::runtime_error("shared_pointer_ctor_index_error");
        }
        ++ref_counts_[ref_index_];
    }
    
    shared_pointer(shared_pointer&& rhs)
        : data_{rhs.data_}, ref_index_{rhs.ref_index_} {}
    
    shared_pointer& operator=(const shared_pointer& rhs)
    {
        data_ = rhs.data_;
        ref_index_ = rhs.ref_index_;
        if (ref_index_ >= ref_counts_.size())
        {
            throw std::runtime_error("shared_pointer_ctor_index_error");
        }
        ++ref_counts_[ref_index_];
    }
    
    shared_pointer& operator=(shared_pointer&& rhs)
    {
        data_ = rhs.data_;
        ref_index_ = rhs.ref_index_;
    }
    
    ~shared_pointer()
    {
        if (ref_counts_[ref_index_] == 0)
        {
            std::logic_error("shared_point_dtor_reference_counting_error");
        }
        --ref_counts_[ref_index_];
        if (ref_counts_[ref_index_] == 0)
        {
            std::free(data_);
        }
    }
    
    // main functionality
    
    Tres_t* data()
    {
        return data_;
    }
    
    const Tres_t* data() const
    {
        return data_;
    }
};

template<class Tres_t>
std::vector<std::size_t> shared_pointer<Tres_t>::ref_counts_ = {};

#endif

I've tested this code only rudimentarily so I'll leave it to you to test and improve it.

Nitin Malapally
  • 534
  • 2
  • 10
  • `shared_pointer` and similar non-trivial types will not work, due to you using `malloc`. The code has undefined behavior, since no objects would have actually been created. – PaulMcKenzie May 21 '22 at 11:20
  • Ah yes. The operator 'new' is better here. In the best case, the user should be able to provide an allocator and a deleter. – Nitin Malapally May 21 '22 at 13:06
  • @PaulMcKenzie so what should i do for malloc , calloc and realloc allocations ? – esmaeil.zivari May 21 '22 at 19:11
  • @NitinMalapally if we want to use first solution that you said and don't use a class ? what should i do ? do you have any idea ? – esmaeil.zivari May 22 '22 at 05:35
  • @esmaeil.zivari you'd have `ref_counts_` as a global variable in a source file, you'll need to define a struct called `shared_pointer` which contains `data_` and `ref_index_`. Then you'd have `create`, `copy` and `destroy` functions which take an instance of `shared_pointer` as parameter. These would do the same work which the constructors and destructor from the above code do. – Nitin Malapally May 22 '22 at 05:56
  • @NitinMalapally sorry i have another question .what about functions that use a pointer as a argument or return a pointer .how we can trace and count reference count of that pointers ? like if p was a pointer and we have functions like f(p) or f(){ return p } . before we release p we should sure that this functions dosnt use that pointer – esmaeil.zivari Jun 04 '22 at 09:44