Suppose I want to write something a function such that:
static
.What is the best to write this function, with the requirements that:
new
raw pointers. If pointers are required, they must be smart and auto deleteThe use case is the following:
The caller should not know which values are common, the interface should be transparent for both cases.
So far, the only clean implementation that I've managed is to use shared_ptr
as shown below, but it feels like overkill. In particular, because it makes a heap allocation, where it feels that one is not really required. Is there a better approach?
#include <cassert>
#include <iostream>
#include <memory>
struct C {
int i;
static int count;
C(int i) : i(i) {
std::cout << "constr" << std::endl;
count++;
}
C(const C& c) : C(c.i) {
std::cout << "copy" << std::endl;
}
~C() {
std::cout << "destr" << std::endl;
count--;
}
};
int C::count = 0;
std::shared_ptr<C> func_reg_maybe_static(int i) {
static auto static_obj = std::make_shared<C>(0);
if (i == 0) {
return static_obj;
} else {
return std::make_shared<C>(i);
}
}
int main() {
assert(C::count == 0);
{
auto c(func_reg_maybe_static(0));
assert(c->i == 0);
assert(C::count == 1);
}
assert(C::count == 1);
{
auto c(func_reg_maybe_static(0));
assert(c->i == 0);
assert(C::count == 1);
}
assert(C::count == 1);
{
auto c(func_reg_maybe_static(1));
assert(c->i == 1);
assert(C::count == 2);
}
assert(C::count == 1);
{
auto c(func_reg_maybe_static(2));
assert(c->i == 2);
assert(C::count == 2);
}
assert(C::count == 1);
}
Which I compile with GCC 6.4.0:
g++ -std=c++17 -Wall -Wextra -pedantic-errors -o main.out func_ret_maybe_static.cpp
and it produces the expected output (guaranteed by copy elision I believe):
constr
constr
destr
constr
destr
destr
I've added the static reference counter C::count
just to check that objects are actually getting deleted as expected.
If I didn't have the static case, I would just do directly:
C func_reg_maybe_static(int i) {
return C(i);
}
and copy elision / move semantics would make everything efficient.
However, if I try something analogous as in:
C func_reg_maybe_static(int i) {
static C c(0);
return c;
}
then C++ smartly stops just moving C, and starts to copy it, to avoid corrupting the static
.
I don't really understand the purpose of the static/automatic stuff. If all you're trying to do is avoid repeated constructions when the argument has been used before, why not just have a cache instead?
C& func_reg(const int i)
{
static std::unordered_map<int, C> cache;
auto it = cache.find(i);
if (it == cache.end())
it = cache.emplace(i, C(i));
return it->second;
}
Don't always want the cache? Fine! Add this:
C func_reg_nocache(const int i)
{
return C(i);
}
If I've misunderstood and you really need this thing where passing is_static == true
gives you an entirely different object (one constructed with 0
rather than i
) then just make a new function for that; it's doing something distinct.
C& func_reg()
{
static C obj(0);
return obj;
}
C func_reg(const int i)
{
return C(i);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With