- copy constructor and move constructor - 4 Updates
- Reading from a large file by multiple reads of small chunks - 4 Updates
- template classes and .h file - 2 Updates
Sui Huang <hailiyouyu.hs@gmail.com>: Sep 20 06:15AM -0700 Hi everyone, I got trouble with copy or move operations. I wrote a class HasPtr when learning chapter 13 of <C++ Primer>. /* header file */ class HasPtr{ public: HasPtr(const std::string &str = std::string()) : ps(new std::string(str)), val(0) {std::cout << "default constructor";} HasPtr(const HasPtr &); //output "copy constructor" HasPtr(HasPtr &&) noexcept; //output "move constructor" HasPtr &operator=(const HasPtr &); //output "copy assignment" HasPtr &operator=(HasPtr &&) noexcept; //output "move assignment" ~HasPtr(); private: std::string *ps; int val; }; I have implemented HasPtr correctly, in each member function, print the function name. And I cann't understand these outputs that : /* test code */ #1. HasPtr ptr = HasPtr(); //call "Default Constructor" #2. HasPtr ptr2(HasPtr()); //outpus nothing #3. vector<HasPtr> items = {HasPtr("abc"), HasPtr("def")}; //first call default constructor, then copy constructor #1. I think right side object is rvalue, why not first call default then move constructor? #2. I think this should work like #1. #3. When copy objects to vector, why not call move constructor? By the way, my compile environment is gcc 4.9.2 in Ubuntu 15.04 |
"Öö Tiib" <ootiib@hot.ee>: Sep 20 08:12AM -0700 On Sunday, 20 September 2015 16:15:51 UTC+3, Sui Huang wrote: > Hi everyone, I got trouble with copy or move operations. No. You got trouble with most vexing parse. https://en.wikipedia.org/wiki/Most_vexing_parse > #2. HasPtr ptr2(HasPtr()); //outpus nothing There you declare a function. |
mark <mark@invalid.invalid>: Sep 20 07:37PM +0200 On 2015-09-20 15:15, Sui Huang wrote: > #3. vector<HasPtr> items = {HasPtr("abc"), HasPtr("def")}; //first call default constructor, then copy constructor > [...] > #3. When copy objects to vector, why not call move constructor? Initializer lists don't support move, the elements can only be accessed as const and thus must be copied. There is a proposal to support move, so this may be possible in C++17. |
Paavo Helde <myfirstname@osa.pri.ee>: Sep 20 02:34PM -0500 Sui Huang <hailiyouyu.hs@gmail.com> wrote in > #1. HasPtr ptr = HasPtr(); //call "Default Constructor" > #1. I think right side object is rvalue, why not first call default > then move constructor? Most probably the move constructor has been optimized away and the object is constructed directly in the right place. Others have already answered other questions. |
Paul <pepstein5@gmail.com>: Sep 20 01:26AM -0700 On Saturday, September 19, 2015 at 11:49:42 PM UTC+1, Jens Thoms Toerring wrote: > carded. So the function, as it is, satisfies the requi- > rements by the letter, but probably isn't what was ex- > pected. ... Jens, Many many thanks for such a thoughtful and helpful analysis. However, a few questions still remain. I understand you as saying that the below is correct. char readbuf[ 4096 ]; int num_read = Read4096( readbuf ); However, it seems (to me) to read from an array of uninitialized chars. That's why I wanted to read from buf rather than from the uninitialized array. Also, (assuming that we're aiming for an initial simplified version that isn't concerned with repeated calls), I don't see why the final piece of the file (past the chunks of 4096) needs to be treated differently (by being copied into a separate buffer). Why not the code below? Many thanks, Paul CODE AS ABOVE WITH SUGGESTED (AND PROBABLY ERRONEOUS) SIMPLIFICATIONS int read(char* buf, int n){ int num_it = n / 4096; int total = 0; for(int i = num_it; num_it >= 0; --num_it){ int num_read = read4096(buf); total += num_read; buf += num_read; if(num_read == 0) break; } return total; } |
Kalle Olavi Niemitalo <kon@iki.fi>: Sep 20 12:04PM +0300 > char readbuf[ 4096 ]; > int num_read = Read4096( readbuf ); > However, it seems (to me) to read from an array of uninitialized chars. That code does not read from the array. The expression Read4096(readbuf) means the same thing as Read4096(&readbuf[0]); the array "decays" to a pointer that points to the first element of the array. Only that pointer is passed to the function Read4096, which then uses it to write to the array. The same thing would happen in fread(readbuf, 1, 4096, file). > Why not the code below? Consider what happens if someone calls it like this, and the file actually is 50 bytes long; char smallbuf[10]; int got = read(smallbuf, 10); The intended effect is that the first 10 bytes of the file should be read to smallbuf. > int read(char* buf, int n){ > int num_it = n / 4096; > int total = 0; This would set num_it = 0 and total = 0. > for(int i = num_it; num_it >= 0; --num_it){ This would set i = 0 and enter the loop body. > int num_read = read4096(buf); This would try to read 4096 bytes to buf, which points to smallbuf. Because the file is 50 bytes long, read4096 would read only 50 bytes to smallbuf. But smallbuf only has room for 10 bytes, so read4096 would write past the end of smallbuf and likely corrupt some other object. |
jt@toerring.de (Jens Thoms Toerring): Sep 20 10:13AM > However, it seems (to me) to read from an array of uninitialized chars. > That's why I wanted to read from buf rather than from the uninitialized > array. As Kalle has already pointed out, this doesn't read from 'readbuf' - the Read4096() function reads from a file (up to 4096 bytes) and puts them into the buffer you call it with. So it will write what it read into 'readbuf'. > } > return total; > } The problem is the buffer the caller passes to the function. The user isn't supposed to know how the function works in- ternally. So it's reasonable for him to assume that the buffer he or she passes to the function doesn't have to be larger than the number of bytes he requests. And for that reason alone the function may never try to write more than as many bytes as the user requested into the buffer supplied by him (or her). Consider an attempt by the user to read the file character by character, similar to fgetc(). So he might do char c; while ( read( &c, 1 ) == 1 ) do_something_with_the_character( c ) The user expects to get exactly one character (or nothing when the end of the file has been reached). But your ver- sion of the function would try to stuff up to 4096 bytes into the location of 'c' where there's room for just a single character (thus writing over the memory following it, pos- sibly destroying other important data, smashing the stack etc.) and would return a number between 0 and 4096, depen- ding on how much was still available in the file. But the user had no reason to expect that the function would return anything but 1 or 0. This type of use case is also why I would consider the function you originally posted to be deficient. While it at least doesn't write past the end of the user supplied buffer and never has a return value larger than the num- ber of characters the user requested, it discards all the characters it read in from the file but could not return to the user. If used in the way shown above, i. e. in an attempt to read in the file character by cha- racter, it would return just every 4096th character from the file, which probably isn't what any user of it would expect. To use it properly the user would have to be aware that, to get everything from the file, it must be called with a buffer with a length that's an integer multiple of 4096. And then it probably would be simpler to use Read4096() directly;-) Regards, Jens -- \ Jens Thoms Toerring ___ jt@toerring.de \__________________________ http://toerring.de |
Christian Gollwitzer <auriocus@gmx.de>: Sep 20 02:08PM +0200 Am 19.09.15 um 22:56 schrieb Paul: > Todo: Use above API to Implement API > "int Read(char* buf, int n)" which reads any number of chars from the file. > Below is a solution offered by someone posting at that site. I have questions about this as follows. Others have already pointed out where this solution is insufficient. I'd like to add: this solution tries to optimize away copying by calling read4096 directly into the output bufer, if possible. For sure this can be done, and it'll be a little more efficient than copying - but it would be far easier to get it correct with a "static char readbuf[4096]" and a "static size_t readbufindex" that points to the first byte not-yet retrieved and a "static char buflength", pointing to the end of the data in readbuf. You then always only fill the buffer if the request cannot be fulfilled from the remaining content. Sure, this will waste a few bytes and make it a bit slower due to copying - but first you should try to implement a correct version, profile, and then maybe optimize. If the read4096 takes lots of time to get the data from the external device, copying might be negligible. Christian |
asetofsymbols@gmail.com: Sep 19 09:30PM -0700 If I have one library file in C++ one .dll: Where I have to put one template class, in the .cpp file that is the .dll or in the .h file I include when I call that .dll from other .cpp files? [I think all in the .h file I use for call that .dll from other .cpp programs] |
Paavo Helde <myfirstname@osa.pri.ee>: Sep 20 02:43AM -0500 asetofsymbols@gmail.com wrote in > .cpp files? > [I think all in the .h file I use for call that .dll from other .cpp > programs] The most simple solution is to put all templates in header files. If most code in a project is in templates, then it might even make sense to put everything in header files and avoid creating a dll altogether. Such libraries are called header-only libraries and for example Boost is full of them. See also https://isocpp.org/wiki/faq/templates#templates-defn-vs-decl hth Paavo |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment