#include <iostream>
class Complex
{
double *arr;
int n;
public:
Complex() :n(0), arr(nullptr) {};
Complex(const Complex &a)
{
if (this != a)
{
this->~Complex();
copy(a);
}
}
void copy(const Complex &a)
{
n = a.n;
arr = new double[n];
std::copy(a.arr, a.arr + n, arr);
}
~Complex()
{
delete[] arr;
n = 0;
}
};
int main()
{
getchar();
getchar();
}
This is the code i have, as you can see, all i did so far is that i created class Complex and i created default constructor and i wanted to create copy constructor, which shouldn't be complicated, but when i tried to compile this, compiler says "no operator '!=' matches these operands" , now, i know that this is a pointer to the ongoing object, and a is my argument that is sent to function by reference, so i am wondering, do i need to treat this argument inside of a function as a regular variable even though it is sent as a reference? Could that be the problem? Or is it something else? Any help appreciated!
The line
if (this != a)
is a syntactic error since type of this is a pointer while a is a reference to an object. A syntactially correct form would be:
if (this != &a)
However, that is totally unnecessary in a copy constructor. In the copy constructor, you are creating a new object from another object. this != &a will always be true.
Secondly, don't use
this->~Complex();
in the function. You have not yet constructed the object. What sense does it make to call the destructor on it? Also, once you have called the destructor, the object is dead. Using the object after that is cause for undefined behavior.
Simlify your function to:
Complex(const Complex &a)
{
copy(a);
}
A constructor's job is to initialize an object under creation. There is no pre-existing object there yet, so doing the check this != &a is pointless (I fixed it to compare addresses, as you probably meant). The only way that condition will ever be false is if someone writes this Machiavellian piece of code
Complex a(a);
It's technically allowed but any compiler worth its salt will flag it with a nice shiny warning that this line needs to be fixed.
Now, because there is no object there yet (it is being created), calling its destructor makes your program have undefined behavior. It means you can't predict what will happen according to the C++ specification, which puts you on very shaky ground.
A straight forward constructor will do the job just fine:
Complex(const Complex &a) : n(a.n), arr(new double[a.n])
{
std::copy(a.arr, a.arr + n, arr);
}
Protect against Murphy, not Machiavelli. Defensive programming is good to stop someone from accidentally braking your code. But you can't stop someone intent on it, so don't write overly complex checks to try.
No, in if (this != a) you have this that is a pointer and a that is a reference.
Do: if (this != &a)
Related
I'm asking something that looks trivial but I had problems with. Let's assume, for the sake of explanation, a structure like this one:
class MyClass{
int* m_Number;
public:
int value() const {return *m_Number;}
void setValue(int val){*m_Number=val;}
MyClass() : m_Number(new int(3)){}
~MyClass() {if(m_Number) delete m_Number;}
MyClass(const MyClass& other):m_Number(new int(*other.m_Number)){}
MyClass& operator=(const MyClass& other){if(m_Number) *m_Number=*other.m_Number; else m_Number=new int(*other.m_Number); return *this;}
MyClass& operator=(MyClass&& other){std::swap(m_Number,other.m_Number); return *this;}
MyClass(MyClass&& other){
//????
}
}
What should I put in there?
My options are:
1)
MyClass(MyClass&& other)
:m_Number(other.m_Number)
{
other.m_Number=nullptr;
}
But then the moved from object is not in a valid state. calling value() should return something valid but undetermined while here I just segfault. I could check m_Number in value() and setValue() but you realise it's a huge drag in real code.
2)
MyClass(MyClass&& other)
:m_Number(other.m_Number)
{
other.m_Number= new int(3);
}
But a move constructor that can throw is a no go (or at least as I understand it) and it's also a drag of the performance enhancement, in fact this code is equal or worse that the copy constructor.
What do you think?
Did I miss something?
Is there a preferred way to go?
Thanks in advance
Edit: This question received an answer from the convener of the std committee and it fundamentally disagrees with the answers to this post. You can find it in this article https://herbsutter.com/2020/02/17/move-simply/
Firstly, there's no reason to use new and delete here, you should be using make_unique<int> to create the object and a unique_ptr<int> to manage it automatically. But that doesn't solve your problem, of what the move constructor can do. There are some other options in addition to the two you suggest:
3) don't give it a move constructor, just leave it as copyable
4) document that calling value or setValue on a moved-from object is not allowed, and leave the moved-from object with a null pointer. Depending where moves happen in your program that might be fine. If moved-from objects are never accessed, everything just works.
4a) As above, but add sanity checks in case it does ever happen:
int value() const {
assert(m_Number != nullptr);
return *m_Number;
}
or:
int value() const {
if (m_Number == nullptr)
throw std::logic_error("accessed a moved-from object");
return *m_Number;
}
5) Add checks to setValue to re-initialize the object with a new int if it's currently null, and make value return some default value:
int value() const { return m_Number ? *m_Number : 0; }
void setValue(int val) {
if (!m_Number)
m_Number = new int(val);
else
*m_Number = val;
}
You are dereferencing your pointer in the .value() call. You will always segfault in the event that m_Number is invalid.
Your first solution to the move constructor is correct, you should set the 'other' object to a default state. To solve this, you could make your .value() method throw, or return a default value in the event of non-existent resource.
Your destructor already accounts for the null case, so make sure the rest of it accounts for it as well.
Your first approach is probably the best if modifying MyClass such that m_Number = nullptr is a valid state is reasonable to do (and would be best practice if it were the default state too). I'd argue if having no-heap memory associated with MyClass is not a valid state, you should be allocating it inside of a std::unique_ptr, and passing around a raw pointer to that instead of implementing a move constructor.
If 1. is not an option, this is a reasonable way to go. While there certainly is a performance hit for allocating un-needed memory, it is quite minor, especially considering you are constructing a class as part of this operation (which itself requires memory). If its a small chunk of memory that is needed as in your example, the memory allocator will likely draw it from its own pool without the need of a system call. If it is a large chunk of memory (as I would expect since you're implementing move semantics), then on most modern operating systems it will be a lazy allocation (so it would still be better than a copy constructor).
Do not use raw owning pointers, convert your class to use std::unique_ptr, and all your problems will go away.
I'm having a trouble overloading operator [] for both read and write in my objects. This is a large code with different components and I'm not going to put all the details here since it wont help. In a nutshell what I have is the following
class MyObject(){
inline SetterProxy& operator[](int i) {
SetterProxy a(i);
return a;
}
inline double operator[](int i) const{
return some_value;
}
}
The first overloaded [] works fine for assigning values (if you are wondering what the SetterProxy is, I have to use Proxy classes to be able to do some checking and internal function calls before assigning values). However, the second one which should supposedly be called when reading does not work and the code crashes. I'm not sure what is happening here but when I comment out the first one it just works fine! Could it be that compiler somehow confuses the two since they are both inline?
Any thought would be appreciated.
EDIT:
Ok here is the SetterProxy itself:
class SetterProxy{
private:
Vec v;
int i;
double *ptr_val;
public:
inline SetterProxy(Vec v_, int i_) {
v = v_;
i = i_;
VecGetArray(v,&ptr_val);
}
inline ~SetterProxy(){
VecRestoreArray(v,&ptr_val);
}
inline void operator=(double rhs ){
ptr_val[i] = rhs;
}
};
Although I dont think its coming directly from that. Also initially I had it to return by value and I though changing it to reference would be more efficient. I think this should be safe since the assignment is done in the Proxy operator=() class and after that the proxy class goes out of scope. Either way, that does not save my problem!
You're returning a reference to a local variable - it goes out of scope when the operator returns, leaving your reference dangling. A good compiler should warn you about this if you turn the warning setting up to a reasonable level.
As noted in #Stuart Golodetz's answer, you are returning a reference to SetterProxy referring to a, which is local to your method and thus goes out of scope when it returns.
You should instead return a SetterProxy instance by value: that shouldn't be a big deal, SetterProxy will probably just hold the index and a reference to the "parent" object, so the compiler-generated copy constructor for it will be fine and the copy won't be costly at all.
By the way, unless you want to allow negative indexes, the usual idiom is to use size_t for indexes in arrays.
The most interesting C++ question I've encountered recently goes as follows:
We determined (through profiling) that our algorithm spends a lot of time in debug mode in MS Visual Studio 2005 with functions of the following type:
MyClass f(void)
{
MyClass retval;
// some computation to populate retval
return retval;
}
As most of you probably know, the return here calls a copy constructor to pass out a copy of retval and then the destructor on retval. (Note: the reason release mode is very fast for this is because of the return value optimization. However, we want to turn this off when we debug so that we can step in and nicely see things in the debugger IDE.)
So, one of our guys came up with a cool (if slightly flawed) solution to this, which is, create a conversion operator:
MyClass::MyClass(MyClass *t)
{
// construct "*this" by transferring the contents of *t to *this
// the code goes something like this
this->m_dataPtr = t->m_dataPtr;
// then clear the pointer in *t so that its destruction still works
// but becomes 'trivial'
t->m_dataPtr = 0;
}
and also changing the function above to:
MyClass f(void)
{
MyClass retval;
// some computation to populate retval
// note the ampersand here which calls the conversion operator just defined
return &retval;
}
Now, before you cringe (which I am doing as I write this), let me explain the rationale. The idea is to create a conversion operator that basically does a "transfer of contents" to the newly constructed variable. The savings happens because we're no longer doing a deep copy, but simply transferring the memory by its pointer. The code goes from a 10 minute debug time to a 30 second debug time, which, as you can imagine, has a huge positive impact on productivity. Granted, the return value optimization does a better job in release mode, but at the cost of not being able to step in and watch our variables.
Of course, most of you will say "but this is abuse of a conversion operator, you shouldn't be doing this kind of stuff" and I completely agree. Here's an example why you shouldn't be doing it too (this actually happened:)
void BigFunction(void)
{
MyClass *SomeInstance = new MyClass;
// populate SomeInstance somehow
g(SomeInstance);
// some code that uses SomeInstance later
...
}
where g is defined as:
void g(MyClass &m)
{
// irrelevant what happens here.
}
Now this happened accidentally, i.e., the person who called g() should not have passed in a pointer when a reference was expected. However, there was no compiler warning (of course). The compiler knew exactly how to convert, and it did so. The problem is that the call to g() will (because we've passed it a MyClass * when it was expecting a MyClass &) called the conversion operator, which is bad, because it set the internal pointer in SomeInstance to 0, and rendered SomeInstance useless for the code that occured after the call to g(). ... and time consuming debugging ensued.
So, my question is, how do we gain this speedup in debug mode (which has as direct debugging time benefit) with clean code that doesn't open the possibility to make such other terrible errors slip through the cracks?
I'm also going to sweeten the pot on this one and offer my first bounty on this one once it becomes eligible. (50 pts)
You need to use something called "swaptimization".
MyClass f(void)
{
MyClass retval;
// some computation to populate retval
return retval;
}
int main() {
MyClass ret;
f().swap(ret);
}
This will prevent a copy and keep the code clean in all modes.
You can also try the same trick as auto_ptr, but that's more than a little iffy.
If your definition of g is written the same as in your code base I'm not sure how it compiled since the compiler isn't allowed to bind unnamed temporaries to non-const references. This may be a bug in VS2005.
If you make the converting constructor explicit then you can use it in your function(s) (you would have to say return MyClass(&retval);) but it won't be allowed to be called in your example unless the conversion was explicitly called out.
Alternately move to a C++11 compiler and use full move semantics.
(Do note that the actual optimization used is Named Return Value Optimization or NRVO).
The problem is occuring because you're using MyClass* as a magic device, sometimes but not always. Solution: use a different magic device.
class MyClass;
class TempClass { //all private except destructor, no accidental copies by callees
friend MyClass;
stuff* m_dataPtr; //unfortunately requires duplicate data
//can't really be tricked due to circular dependancies.
TempClass() : m_dataPtr(NULL) {}
TempClass(stuff* p) : m_dataPtr(p) {}
TempClass(const TempClass& p) : m_dataPtr(p) {}
public:
~TempClass() {delete m_dataPtr;}
};
class MyClass {
stuff* m_dataPtr;
MyClass(const MyClass& b) {
m_dataPtr = new stuff();
}
MyClass(TempClass& b) {
m_dataPtr = b.m_dataPtr ;
b.m_dataPtr = NULL;
}
~MyClass() {delete m_dataPtr;}
//be sure to overload operator= too.
TempClass f(void) //note: returns hack. But it's safe
{
MyClass retval;
// some computation to populate retval
return retval;
}
operator TempClass() {
TempClass r(m_dataPtr);
m_dataPtr = nullptr;
return r;
}
Since TempClass is almost all private (friending MyClass), other objects cannot create, or copy TempClass. This means the hack can only be created by your special functions when clearly told to, preventing accidental usage. Also, since this doesn't use pointers, memory can't be accidentally leaked.
Move semantics have been mentioned, you've agreed to look them up for education, so that's good. Here's a trick they use.
There's a function template std::move which turns an lvalue into an rvalue reference, that is to say it gives "permission" to move from an object[*]. I believe you can imitate this for your class, although I won't make it a free function:
struct MyClass;
struct MovableMyClass {
MyClass *ptr;
MovableMyClass(MyClass *ptr) : ptr(ptr) {}
};
struct MyClass {
MyClass(const MovableMyClass &tc) {
// unfortunate, we need const reference to bind to temporary
MovableMyClass &t = const_cast<MovableMyClass &>(tc);
this->m_dataPtr = t.ptr->m_dataPtr;
t.ptr->m_dataPtr = 0;
}
MovableMyClass move() {
return MovableMyClass(this);
}
};
MyClass f(void)
{
MyClass retval;
return retval.move();
}
I haven't tested this, but something along those lines. Note the possibility of doing something const-unsafe with a MovableMyClass object that actually is const, but it should be easier to avoid ever creating one of those than it is to avoid creating a MyClass* (which you've found out is quite difficult!)
[*] Actually I'm pretty sure I've over-simplified that to the point of being wrong, it's actually about affecting what overload gets chosen rather than "turning" anything into anything else as such. But causing a move instead of a copy is what std::move is for.
A different approach, given your special scenario:
Change MyClass f(void) (or operator+) to something like the following:
MyClass f(void)
{
MyClass c;
inner_f(c);
return c;
}
And let inner_f(c) hold the actual logic:
#ifdef TESTING
# pragma optimize("", off)
#endif
inline void inner_f(MyClass& c)
{
// actual logic here, setting c to whatever needed
}
#ifdef TESTING
# pragma optimize("", on)
#endif
Then, create an additional build configurations for this kind of testing, in which TESTING is included in the preprocessor definitions.
This way, you can still take advantage of RVO in f(), but the actual logic will not be optimized on your testing build. Note that the testing build can either be a release build or a debug build with optimizations turned on. Either way, the sensitive parts of the code will not be optimized (you can use the #pragma optimize in other places too, of course - in the code above it only affects inner_f itself, and not code called from it).
Possible solutions
Set higher optimization options for the compiler so it optimizes out the copy construction
Use heap allocation and return pointers or pointer wrappers, preferably with garbage collection
Use the move semantics introduced in C++11; rvalue references, std::move, move constructors
Use some swap trickery, either in the copy constructor or the way DeadMG did, but I don't recommend them with a good conscience. An inappropriate copy constructor like that could cause problems, and the latter is a bit ugly and needs easily destructible default objects which might not be true for all cases.
+1: Check and optimize your copy constructors, if they take so long then something isn't right about them.
I would prefer to simply pass the object by reference to the calling function when MyClass is too big to copy:
void f(MyClass &retval) // <--- no worries !
{
// some computation to populate retval
}
Just simple KISS principle.
Okay I think I have a solution to bypass the Return Value Optimization in release mode, but it depends on the compiler and not guaranteed to work. It is based on this.
MyClass f (void)
{
MyClass retval;
MyClass dummy;
// ...
volatile bool b = true;
if b ? retval : dummy;
}
As for why the copy construction takes so long in DEBUG mode, I have no idea. The only possible way to speed it up while remaining in DEBUG mode is to use rvalue references and move semantics. You already discovered move semantics with your "move" constructor that accepts pointer. C++11 gives a proper syntax for this kind of move semantics. Example:
// Suppose MyClass has a pointer to something that would be expensive to clone.
// With move construction we simply move this pointer to the new object.
MyClass (MyClass&& obj) :
ptr (obj.ptr)
{
// We set the source object to some trivial state so it is easy to delete.
obj.ptr = NULL;
}
MyClass& operator = (MyClass&& obj) :
{
// Here we simply swap the pointer so the old object will be destroyed instead of the temporary.
std::swap(ptr, obj.ptr);
return *this;
}
Today in university I was recommended by a professor that I'd check for (this != ©) in the copy constructor, similarly to how you should do it when overloading operator=. However I questioned that because I can't think of any situation where this would ever be equal to the argument when constructing an object.
He admitted that I made a good point. So, my question is, does it make sense to perform this checking, or is it impossible that this would screw up?
Edit: I guess I was right, but I'll just leave this open for a while. Maybe someone's coming up with some crazy cryptic c++ magic.
Edit2: Test a(a) compiles on MinGW, but not MSVS10. Test a = a compiles on both, so I assume gcc will behave somewhat similar. Unfortunately, VS does not show a debug message with "Variable a used without being initialized". It does however properly show this message for int i = i. Could this actually be considered a c++ language flaw?
class Test
{
Test(const Test ©)
{
if (this != ©) // <-- this line: yay or nay?
{
}
}
Test &operator=(const Test &rhd)
{
if (this != &rhd) // <-- in this case, it makes sense
{
}
}
};
Personally, I think your professor is wrong and here's why.
Sure, the code will compile. And sure, the code is broken. But that's as far as your Prof has gone with his reasoning, and he then concludes "oh well we should see if we're self-assigning and if we are, just return."
But that is bad, for the same reason why having a global catch-all catch(...) which does nothing is Evil. You're preventing an immediate problem, but the problem still exists. The code is invalid. You shouldn't be calling a constructor with a pointer to self. The solution isn't to ignore the problem and carry on. The solution is to fix the code. The best thing that could happen is your code will crash immediately. The worst thing is that the code will continue in an invalid state for some period of time and then either crash later (when the call stack will do you no good), or generate invalid output.
No, your professor is wrong. Do the assignment without checking for self-assignment. Find the defect in a code review or let the code crash and find it in a debug session. But don't just carry on as if nothing has happened.
This is valid C++ and calls the copy constructor:
Test a = a;
But it makes no sense, because a is used before it's initialized.
If you want to be paranoid, then:
class Test
{
Test(const Test ©)
{
assert(this != ©);
// ...
}
};
You never want to continue if this == ©. I've never bothered with this check. The error doesn't seem to frequently occur in the code I work with. However if your experience is different then the assert may well be worth it.
Your instructor is probably trying to avoid this situtation -
#include <iostream>
class foo
{
public:
foo( const foo& temp )
{
if( this != &temp )
std::cout << "Copy constructor \n";
}
};
int main()
{
foo obj(obj); // This is any how meaning less because to construct
// "obj", the statement is passing "obj" itself as the argument
}
Since the name ( i.e., obj ) is visible at the time declaration, the code compiles and is valid.
Your instructor may be thinking of the check for self-assignment in the copy assignment operator.
Checking for self-assignment in the assignment operator is recommended, in both Sutter and Alexandrescu's "C++ Coding Standards," and Scott Meyer's earlier "Effective C++."
In normal situations, it seems like here is no need to. But consider the following situation:
class A{
char *name ;
public:
A & operator=(const A & rhs);
};
A & A::operator=(const A &rhs){
name = (char *) malloc(strlen(rhs.name)+1);
if(name)
strcpy(name,rhs.name);
return *this;
}
Obviously the code above has an issue in the case when we are doing self assignment. Before we can copy the content, the pointer to the original data will be lost since they both refer to same pointer. And that is why we need to check for self assignment. Function should be like
A & A::operator=(const A &rhs){
if(this != &rhs){
name = (char *) malloc(strlen(rhs.name)+1);
if(name)
strcpy(name,rhs.name);
}
return *this;
}
When writing assignment operators and copy constructors, always do this:
struct MyClass
{
MyClass(const MyClass& x)
{
// Implement copy constructor. Don't check for
// self assignment, since &x is never equal to *this.
}
void swap(MyClass& x) throw()
{
// Implement lightweight swap. Swap pointers, not contents.
}
MyClass& operator=(MyClass x)
{
x.swap(*this); return *this;
}
};
When passing x by value to the assignment operator, a copy is made. Then you swap it with *this, and let x's destructor be called at return, with the old value of *this. Simple, elegant, exception safe, no code duplication, and no need for self assignment testing.
If you don't know yet about exceptions, you may want to remember this idiom when learning exception safety (and ignore the throw() specifier for swap for now).
I agree that self check doesn't make any sense in copy constructor since object isn't yet created but your professor is right about adding the check just to avoid any further issue. I tried with/without self check and got unexpected result when no self check and runtime error if self check exists.
class Test
{
**public:**
Test(const Test& obj )
{
size = obj.size;
a = new int[size];
}
~Test()
{....}
void display()
{
cout<<"Constructor is valid"<<endl;
}
**private:**
}
When created copy constructor and called member function i didn
Test t2(t2);
t2.display();
Output:
Inside default constructor
Inside parameterized constructor
Inside copy constructor
Constructor is valid
This may be correct syntactically but doesn't look right.
With self check I got runtime error pointing the error in code so to avoid such situation.
Test(const Test& obj )
{
if(this != &obj )
{
size = obj.size;
a = new int[size];
}
}
Runtime Error:
Error in `/home/bot/1eb372c9a09bb3f6c19a27e8de801811': munmap_chunk(): invalid pointer: 0x0000000000400dc0
Generally, the operator= and copy constructor calls a copy function, so it is possible that self-assignment occurs.
So,
Test a;
a = a;
For example,
const Test& copy(const Test& that) {
if (this == &that) {
return *this
}
//otherwise construct new object and copy over
}
Test(const &that) {
copy(that);
}
Test& operator=(const Test& that) {
if (this != &that) { //not checking self
this->~Test();
}
copy(that);
}
Above, when a = a is executed, the operator overload is called, which calls the copy function, which then detects the self assignment.
Writing copy-assignment operators that are safe for self-assignment is in the C++ core guidelines and for a good reason. Running into a self-assignment situation by accident is much easier than some of the sarcastic comments here suggest, e.g. when iterating over STL containers without giving it much thought:
std::vector<Test> tests;
tests.push_back(Test());
tests.resize(10);
for(int i = 0; i < 10; i++)
{
tests[i] = tests[0]; // self when i==0
}
Does this code make sense? Not really.
Can it be easily written through carelessness or in a slightly more complex situation? For sure. Is it wrong? Not really, but even if so... Should the punishment be a segfault and a program crash? Heck no.
To build robust classes that do not segfault for stupid reasons, you must test for self-assignment whenever you don't use the copy-and-swap idiom or some other safe alternative. One should probably opt for copy-and-swap anyway but sometimes it makes sense not to, performance wise. It is also a good idea to know the self-assignment test pattern since it shows in tons of legacy code.
Say, i have a function which returns a reference and i want to make sure that the caller only gets it as a reference and should not receive it as a copy.
Is this possible in C++?
In order to be more clear. I have a class like this.
class A
{
private:
std::vector<int> m_value;
A(A& a){ m_value = a.m_value; }
public:
A() {}
std::vector<int>& get_value() { return m_value; }
};
int main()
{
A a;
std::vector<int> x = a.get_value();
x.push_back(-1);
std::vector<int>& y = a.get_value();
std::cout << y.size();
return 0;
}
Thanks,
Gokul.
You can do what you want for your own classes by making the class non copyable.
You can make an class non copyable by putting the copy constructor and operator= as private or protected members.
class C
{
private:
C(const C& other);
const C& operator=(const C&);
};
There is a good example of making a NonCopyable class here that you can derive from for your own types.
If you are using boost you can also use boost::noncopyable.
Alt solution:
Another solution is to have a void return type and make the caller pass their variable by reference. That way no copy will be made as you're getting a reference to the caller's object.
If your function returns a reference to an object that shouldn't have been copied, then your function already has done what it could do to prevent copying. If someone else calls your function and copies the return value, then either
it's an error the caller made, because the object should never be copied (in which case the return type probably shouldn't have been copyable in the first place), or
it's irrelevant for the caller because the function is only called once in a week (in which case you must not try to cripple your callers' code), or
it's a pretty dumb oversight on the side of the caller (in which case the error will be found by profiling).
For #1, either you return have your own type or you can wrap whatever your return in your own type. Note that the only difference between #2 and #3 is the relevance - and if it's relevant, profiling will find it.
IMO you should not cripple your code by returning a pointer when what you need is a reference. Experienced programmers, seeing the pointer, will immediately ask whether they need to check for a NULL return value, whether the object is allocated dynamically and, if so, who is responsible for cleaning it up.
You should also not blindly forbid copying of whatever you return, if you cannot eliminate the possibility that copying is needed.
In the end it's the old motto, which C++ inherited from C: Trust your users to know what they are doing.
It "depends". Yes, you can hide the copy-constructor (and assignment operator), and your object becomes noncopyable:
struct foo
{
private:
foo(const foo&); // dont define
foo& operator=(const foo&); // dont define
}:
But if you're wondering about one specific function (i.e., normally copyable, but not for this function), no. In fact, what can you do about the caller anyway?
const foo& f = get_foo(); // okay, by reference, but...
foo f2 = foo(foo(foo(foo(foo(foo(f)))))); // :[
If your caller wants to do something, there isn't much you can do to stop it.
In C++11, you can prevent the copy constructor from being called by deleting it:
class A{
public:
A(const A&) = delete;
}
Are you trying to prevent a common typo that causes large objects to accidentally be copied? If so, you could return by pointer instead. Leaving off an & is pretty easy, but it takes a little bit of effort to copy an object from a pointer. OTOH, the resulting code will be uglier, so it's up to you whether it's worth it.