I and my co-coder often forget to pass (large) objects by reference and instead pass by value. This might be hurting performance. Is it possible to configure the compiler to warn me in such cases? Is it possible to detect it automatically in a bunch of c++ source files ... maybe a regex that someone has already written?
UPDATE:
Thanks guys for your helpful answers. One problem with all answers is that they only work for classes I write ... not for existing classes .. like std::vector . I can subclass them, but it would be too tedious
You could declare the copy constructor for the types as private - since the copy ctor is called when passing objects by value, your code will error at compile time at any call-site where you're passing by value.
You can also use the new c++11 support to delete unwanted constructors/destructors, if your compiler supports it. Check out the details here.
If you actually need to use the copy ctor in your code another option is to add a debug break-point within the copy ctor. You can then step through a debug build of your program and check when the copy ctor is called.
Hope this helps.
EDIT: Since you're looking to detect copy-ctor use on the standard containers things are a little less straightforward. You could try something along these lines, which is a super-ugly hack, delegating all std::vector instances through a wrapper class with a disabled copy-ctor.
Note the warnings in the code. I would only use this kind of thing to identify your pass-by-value issues and then delete it - reverting to clean use of std::vector etc.
If you wanted to permanently disable copying of standard containers you could write your own wrapper classes that encapsulate (rather than inherit from) the standard containers.
One way you can do is have your heavy object inherit from class like:
struct heavy {
struct heavy_copy_ctor_invoked {};
heavy(const heavy&) {
typename boost::mpl::print<heavy_copy_ctor_invoked>::type _;
}
};
struct foo : heavy { ...
everytime heavy copy-ctor is called, mpl will throw a warning.
Just make a copy constructor and an operator= of the big object private. In QT they made special macro for that Q_DISABLE_COPY().
Related
I'm trying to make a step based puzzle game (kind of like Baba Is You) and I need to store the state of the level at each step. So I'm using classes for the level, entities and some other things, and I was wondering if I can use default constructors like "Level(Level &&)" or "Level(const Level &)" I saw proposed by autocompletion to make a copy of the level as it is, but I can't grasp how they work from the documentation. The main idea was to have each level have its previous step (the copy of the level at the previous step) as an attribute, so that the game can work out any step recursively.
The question is : is any of this possible?
Because the only other way I see to do this is by making a method for my class that will simply create a new blank level and set all the attributes of this new level to those of the actual level, then return it and store it in the main scope. And this seems to be pretty bad because it requires to have evrything public or another method that sets every private attribute to a new value.
If you want to give a look at the code it's here : https://github.com/Leroymilo/SwapCpp/tree/main/Experimental but it's not really clean since I'm starting in C++, and I believe from what I know that this is more of a technical question that doesn't involve correcting what I did (hopefully).
use default constructors like Level(Level &&) or Level(const Level &)
Level(Level &&) is the move constructor. You don't want that, because you don't want to damage the original object
Level(Level const &) is the copy constructor, which is for making a duplicate of an existing object without altering the original.
This is exactly what you're asking for, and should be covered pretty early by any competent book in the section on writing classes.
for reference, "default constructor" means specifically Level() - the constructor with no arguments. This is a well-known term that should also be described in any competent book.
The compiler-generated versions of these constructors are sometimes described as defaulted (and can be requested like
Level(Level const &) = default;
in situations where they wouldn't be generated automatically, or just to make it explicit) - but it's important not to confuse them with the default constructor (which may itself be defaulted if you don't provide one).
Whether the compiler-generated copy constructor will actually do the right thing for you depends entirely on the data members and semantics of your class, which you haven't shown.
In general, it will work as a shallow copy so long as you don't use owning raw pointers or non-copyable types like std::unique_ptr. The std::shared_ptr is particularly suitable for automatic shallow copying where you want shared ownership.
If you want a deep copy, you either need to write the copy constructor by hand or use (ie, find or write) a deep-copying smart pointer.
Either way, see the Guidelines on Resource Management for recommendations that will help the compiler generate correct constructors and destructors for you.
Why is it recommended that you explicitly declare a copy constructor,even when the compiler makes a public copy constructor when you use objects as parameters , use objects as a return value or even construct an object based on another of the same class?
Copy constructor is needed when object has dynamic memory allocations.
In default c++ compiler creates copy constructor, so when you do not have pointer etc. you do not need to define copy constructor.
Why is it recommended that you explicitly declare a copy constructor,even when the compiler makes a public copy constructor
It isn't.
If you don't have special logic to perform in a copy constructor, you don't need to provide one, and doing so is just noise.
If you do, then obviously you have to write that code by providing your own copy constructor.
Some older texts might propose you declare all special member functions, even if their definitions are empty, because if you want to add meaningful definitions later you then do not change the header that contains the definition for the class. This helps to reduce rebuild times and compatibility issues with projects using your code.
But if this ever happened it would almost certainly because you modified or added some data members, so you'd have to modify the header anyway. And, frankly, such a substantial change to a class's semantics warrants a bit of a careful eye anyway. I don't see the benefit in making code as verbose as possible just for the sake of making changes that shouldn't be completely transparent, transparent.
I have a class that looks like this:
class PasswordCategory
{
public:
PasswordCategory(const std::string&);
~PasswordCategory();
PasswordCategory() = delete;
...
}
This results in a compiler error related to allocators:
error C2280: 'PasswordCategory::PasswordCategory(void)' : attempting
to reference a deleted function File: xmemory0:577
IDE is VS 2013 Community.
I am assuming that this occurs because somewhere else I am using vector of these categories.
std::vector<PasswordCategory> m_categories;
I only insert elements into it using emplace_back(string), however, it seems that the default allocator for PasswordCategory is trying to use the default constructor for PasswordCategory, but since that is deleted, it throws an error.
If I provide the default constructor, it all works fine, but I am wondering how I can mitigate this issue without a default constructor, if at all?
I thought of the following solutions:
Providing a custom allocator for my class that constructs my class. However, this doesn't solve the problem that I want my string argument to be non-optional.
Providing the default constructor that just calls my other constructor with some argument. This also doesn't solve the problem that this argument is non-optional and shouldn't really be defaulted.
Using a vector of references or pointers instead of a vector of values. This seems like the most rational solution, however it introduces the need to manage our memory manually, unless we use unique_ptr or something similiar.
I am wondering if I can somehow prohibit arg-less construction of my class, while still being able to use it in standard containers by value?
Any answers and insights are appreciated, thanks in advance.
P.S. This is for a small project of mine that I am doing in order to better understand C++, where I am trying to avoid most of the common pitfalls and make everything as reliable as possible, so that when I am going to work on a bigger project, it will be easier for me to avoid these common pitfalls. I tried formulating the question in different manners, but didn't find an answer for my question, so instead I'm asking my own one.
std::vector itself doesn't require T to be a DefaultConstructible type:
Until C++ 11:
T must meet the requirements of CopyAssignable and CopyConstructible.
Since C++ 11:
The requirements that are imposed on the elements depend on the actual operations performed on the container. Generally, it is required that element type is a complete type and meets the requirements of Erasable, but many member functions impose stricter requirements.
See this page for details.
You may, however, perform operations on container, that involve creating implicit instances and that's why you get this error. If you can track them and eliminate them, everything should work fine, as default constructor will simply not be required if it is not used.
Considering your proposals:
1. Providing a custom allocator for my class that constructs my class.
This won't help - std::allocator is not responsible for default-contructing elements, because it simply does not define such functionality. See std::allocator::construct.
EDIT
Little mistake here, I didn't noticed small change in C++ 11:
Until C++ 11
void construct( pointer p, const_reference val );
Since C++ 11
template< class U, class... Args >
void construct( U* p, Args&&... args );
2. Providing the default constructor that just calls my other constructor with some argument.
This also doesn't solve the problem that this argument is non-optional and shouldn't really be defaulted.
This is also not fully portable. Some compilers (like VC11) does not support delegating constructors.
3. Using a vector of references or pointers instead of a vector of values.
This seems like the most rational solution, however it introduces the need to manage our memory manually, unless we use unique_ptr or something similiar.
Not quite valid - you can't create container of references. The closest solution would be container, that holds std::reference_wrappers. Container of raw/smart pointer is also an option, but that's the point, where things are started to get messy.
Also, in your original code, there is no need to declare deleted default constructor - if you declare any constructor, it means that there is no default one (unless you define it) and compiler won't generate any.
In principle, you cannot: standard containers require contained objects to be default-constructible. (see comment from Mike Seymour).
In principle you should be able to, unless you use operations that require default construction internally.
That said, you can simply create an empty constructor (that defaults members to something sane/calls another constructor with some arguments). If you write client code correctly, you will not encounter your object, initialized with default values.
The operations that require default construction of objects are usually resize, and a few others that require creating internal objects (i.e. unless you want to reserve an element and use it without initializing it explicitly, you should not have a problem).
For example, I want to declare a class but I want the client to not be able to use the copy constructor (or copy assignment operator)
Both of the following two does not allow the use of the copy constructor:
1.
class Track
{
public:
Track(){};
~Track(){};
private:
Track(const Track&){};
};
2.
class Track
{
public:
Track(){};
~Track(){};
Track(const Track&)=delete;
};
Is one of these ways "more correct" than the other or are equal? Is there any side-effect?
//Does not compile with both the above ways
int main()
{
Track l;
Track p(l);
}
Making it private is the "old" way of doing it. The constructor still exists, but it is private, and can only be invoked from within another class member function.
= delete deletes the constructor. It is not generated by the compiler, and it simply will not exist.
So most likely, = delete is what you want. (although with the caveat that not all compilers support this syntax yet, so if portability is a concern...)
Declaring a copy constructor private still allows member functions of the Track class to copy-construct instances of that class, while making it deleted simply forbids copy-constructing that object.
In C++11, deleting a copy constructor is the right way to express the fact that a class is non-copyable (unless of course it makes sense for you to let member functions of Track, or friends of Track, to copy-construct Track objects).
Making a constructor private was basically a "hack" in the old C++, since it was the only way to prevent users from using them. The ability to delete special member functions was only introduced in C++11, and it's the better and more idiomatic way to say that a class cannot be copied. since it is explicit about the intention.
Private constructors have other uses other than forbidding their use entirely (e.g. they may be called by static class member functions). So just making a constructor private doesn't communicate the intention very well, and the resulting error is not very clear, either.
Your first solution conveys to the reader that the copy-constructor is private and is not to be used.
Your second solution is only valid in C++11. Because of this, I'd say the more portable and readable implementation would be your first, using the private-property.
In the first case, you are essentially declaring a private copy constructor and then not providing any implementation. By declaring them private, non-members cannot copy it.
In the second case, the syntax forbids a copy being made. This is C++ native.
The major difference as a programmer is readability and understanding the code. The first case is redundant, why declare the copy constructor, make it private, and not implement it. The client has to infer a lot here.
You can just use "= delete" and clearly imply what you're trying to do.
Your first approach doesn't prevent the class itself from copying itself. The traditional way to solve this is to declare the copy-constructor private and to leave it unimplemented.
An issue with that, however, is that the intent might not be obvious. Someone reading the code might not understand why an orphaned declaration exists and might mistakenly remove it. Comments can help, as would privately inheriting from boost::noncopyable if Boost is available to you.
The second approach makes the intent obvious and is what you should prefer if you can use C++11.
If you are on C++11, use delete. The reason is that it makes the call explicit and the intent clear. You could still accidentally use a private constructor (e.g. in a restricted set of scopes), but the compiler will forbid you from ever using a deleted constructor.
One issue of the private constructor is that the class and friends can still use it -- this results not in access errors but link errors, which can be hard to trace back to the callsite.
If your necessary toolchains do not support deleted constructors (= delete), you should not define it (as seen in your question) -- only declare it and leave it undefined, e.g.: private: \n Track(const Track&);
I've written a simple linked list because a recent interview programming challenge showed me how rusty my C++ has gotten. On my list I declared a private copy constructor because I wanted to explicitly avoid making any copies (and of course, laziness). I ran in to some trouble when I wanted to return an object by value that owns one of my lists.
class Foo
{
MyList<int> list; // MyList has private copy constructor
public:
Foo() {};
};
class Bar
{
public:
Bar() {};
Foo getFoo()
{
return Foo();
}
};
I get a compiler error saying that MyList has a private copy constructor when I try to return a Foo object by value. Should Return-Value-Optimization negate the need for any copying? Am I required to write a copy constructor? I'd never heard of move constructors until I started looking for solutions to this problem, is that the best solution? If so, I'll have to read up on them. If not, what is the preferred way to solve this problem?
The standard explicitly states that the constructor still needs to be accessible, even if it is optimized away. See 12.8/32 in a recent draft.
I prefer making an object movable and non-copyable in such situations. It makes ownership very clear and explicit.
Otherwise, your users can always use a shared_ptr. Hiding shared ownership is at best a questionable idea (unless you can guarantee all your values are immutable).
The basic problem is that return by value might copy. The C++ implementation is not required by the standard to apply copy-elision where it does apply. That's why the object still has to be copyable: so that the implementation's decision when to use it doesn't affect whether the code is well-formed.
Anyway, it doesn't necessarily apply to every copy that the user might like it to. For example there is no elision of copy assignment.
I think your options are:
implement a proper copy. If someone ends up with a slow program due to copying it then their profiler will tell them, you don't have to make it your job to stop them if you don't want to.
implement a proper move, but no copy (C++11 only).
change getFoo to take a Foo& (or maybe Foo*) parameter, and avoid a copy by somehow mutating their object. An efficient swap would come in handy for that. This is fairly pointless if getFoo really returns a default-constructed Foo as in your example, since the caller needs to construct a Foo before they call getFoo.
return a dynamically-allocated Foo wrapped in a smart pointer: either auto_ptr or unique_ptr. Functions defined to create an object and transfer sole ownership to their caller should not return shared_ptr since it has no release() function.
provide a copy constructor but make it blow up somehow (fail to link, abort, throw an exception) if it's ever used. The problems with this are (1) it's doomed to fail but the compiler says nothing, (2) you're enforcing quality of implementation, so your class doesn't work if someone deliberately disables RVO for whatever reason.
I may have missed some.
The solution would be implementing your own copy constructor that would use other methods of MyList to implement the copy semantics.
... I wanted to explicitly avoid making any copies
You have to choose. Either you can't make copies of an object, like std::istream; then you have to hold such objects in pointers/references, since these can be copied (in C++11, you can use move semantics instead). Or you implement the copy constructor, which is probably easier then solving problems on each place a copy is needed.