can vectors be used without invoking copy constructor?

Hi

I have a vector V which contains objects of type O. Generally, I want to prevent O from being copied so I've made the copy/assignment operators private.

On doing this, I've been getting compiler errors and I'm pretty sure that these relate to V which contains elements of typo O. I assume that V invokes O's copy constructor when using push_back and erase etc which explains the compiler errors.

Is there anyway to make O uncopyable but allow O to be used in V? I think move constructors might be helpful here but I'm not sure.

Thanks
> Is there anyway to make O uncopyable but allow O to be used in V? I think move constructors might be helpful here

Yes. Make it moveable.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <string>
#include <fstream>
#include <type_traits>
#include <vector>

struct A // moveable, but non_copyable
{
    A() = default ;
    explicit A( const std::string& path ) : file(path) {}
    explicit A( std::ofstream&& stm ) : file( std::move(stm) ) {}

    bool can_write() const { return file.is_open() && file ; }

    std::ofstream file ;
    // copy constructor and copy assignment operator are implicitly deleted
};

int main()
{
    std::cout << std::boolalpha
              << "copy constructible? " << std::is_copy_constructible<A>::value << '\n'
              << "copy assignable? " << std::is_copy_assignable<A>::value << '\n'
              << "move constructible? " << std::is_move_constructible<A>::value << '\n'
              << "move assignable? " << std::is_move_assignable<A>::value << "\n\n" ;

    std::vector<A> vec ;
    vec.emplace_back( "123.txt" ) ;
    std::cout << "size: " << vec.size() << " capacity: " << vec.capacity() << '\n' ;

    vec.emplace_back( "456.txt" ) ;
    std::cout << "size: " << vec.size() << " capacity: " << vec.capacity() << '\n' ;

    vec.resize(7) ;
    std::cout << "size: " << vec.size() << " capacity: " << vec.capacity() << '\n' ;

    vec.emplace_back( std::ofstream( "789.txt" ) ) ;
    std::cout << "size: " << vec.size() << " capacity: " << vec.capacity() << '\n' ;

    {
        A a( "abcd.txt" ) ;
        vec.push_back( std::move(a) ) ; // don't use the moved from a after this
        std::cout << "size: " << vec.size() << " capacity: " << vec.capacity() << '\n' ;
    }

    vec.erase( vec.begin()+3, vec.begin()+6 ) ;
    std::cout << "size: " << vec.size() << " capacity: " << vec.capacity() << "\n\n" ;

    for( const A& a : vec ) std::cout << a.can_write() << ' ' ;
    std::cout << '\n' ;
}

http://coliru.stacked-crooked.com/a/51654a0f25cd8b78
https://rextester.com/LHWCA6840
// copy constructor and copy assignment operator are implicitly deleted
Is that because std::ofstream has deleted copy constructor/assignment operator?

In general, you'd prevent A from being copied by deleting the copy constructor and assignment operator, right?
1
2
3
4
5
6
struct A {
    A();
    A(const A&) = delete;
    const A& operator=(const A&) = delete;
    int i;
};




> Is that because std::ofstream has deleted copy constructor/assignment operator?

Yes.


> In general, you'd prevent A from being copied by deleting the copy constructor
> and assignment operator, right?

Yes. In that case, the rule of five would apply.

Because the presence of a user-defined destructor, copy-constructor, or copy-assignment operator prevents implicit definition of the move constructor and the move assignment operator, any class for which move semantics are desirable, has to declare all five special member functions
https://en.cppreference.com/w/cpp/language/rule_of_three#Rule_of_five
Last edited on
Topic archived. No new replies allowed.