Is it possible to force a class to be passed by reference or pointer (C++)?

Viewed 90

I'm not entirely sure what to search for to see if this has been asked, so hopefully it isn't a duplicate.

Supposed I've written a class in C++. Is it possible, by way of constructors or some other internal (to the class) mechanism, to throw a compiler warning when the class is passed to a function not by reference.

The motivation behind this is simply to more forcefully control memory allocations. The class in question has several memory pointers that are allocated during class construction (as well as freed/allocated via various class member functions). The allocations are expensive and I want to warn the developer (well, let's be honest, I want to warn myself) of extraneous data copies. However, there are valid use cases for copying the class in other circumstances (might even be valid use cases for passing by value...though I cannot think of any that are unavoidable).

As an aside, the class can be passed by value - the class copy does work. However, I do not want it to be invoked unless it needs to be. Hence the compiler warning instead of an error.

A contrived example:

class doNotSilentCopy {
public:

    doNotSilentCopy(size_t size) {
        mysize = size;
        dummy = (int*)malloc(mysize);
    };
    doNotSilentCopy() : doNotSilentCopy(0) {};

    doNotSilentCopy(const doNotSilentCopy& rhs) {
        this->mysize = rhs.mysize;
        this->dummy = (int*)malloc(this->mysize);
    };

    ~doNotSilentCopy(void) {
        if (dummy) {
            free(dummy);
            dummy = nullptr;
            mysize = 0;
        }
    };

    int get(int index) {
        return *(dummy + index);
    };

private:
    size_t mysize;
    int* dummy;
};

int getDataBad(doNotSilentCopy cls, int index) {
    return cls.get(index);
}

int getDataGood(doNotSilentCopy& cls, int index) {
    return cls.get(index);
}

int main() {
    doNotSilentCopy mycls(10);

    int can_I_warn_about_this = getDataBad(mycls, 5);

    int this_is_acceptable = getDataGood(mycls, 5);

    return 0;
}
2 Answers

To get an error, you'd delete copy construction and copy assignment. You've said you want to retain them, but discourage their use.

Fortunately, modern C++ has an answer for that as well--the deprecated attribute:

[[deprecated("Please avoid copying objects of this class")]]
DoNotSilentCopy(DoNotSilentCopy const &foo);

[[deprecated("Please avoid copying objects of this class")]]
DoNotSilentCopy &operator=(DoNotSilentCopy const &);

Note, however, that this will result in a warning for any copy of the object, not just when it's passed as a parameter.

Visual Studio implemented this starting with VS 2015.

Reference

https://docs.microsoft.com/en-us/cpp/cpp/attributes?view=msvc-160

While I was typing this "van dench" gave the short answer. And what Ted Lyngmo also makes sense. This is the answer in code if you want to be explicit.

class NonCopyableNonMoveable
{
public:
    NonCopyableNonMoveable() = default;
    NonCopyableNonMoveable(NonCopyableNonMoveable&&) = delete;
    NonCopyableNonMoveable& operator=(const NonCopyableNonMoveable&) = delete;
    ~NonCopyableNonMoveable() = default;

    NonCopyableNonMoveable Clone()
    {
        return NonCopyableNonMoveable(*this);
    }

private:
    NonCopyableNonMoveable(const NonCopyableNonMoveable&) = default;
};

void f(NonCopyableNonMoveable c)
{
}

int main()
{
    NonCopyableNonMoveable l;
    // f(l); // <== wont compile
    auto copy_of_l = l.Clone();

    return 0;
}
Related