I'm writing a native module using node-addon-api that takes advantage of the Magick++ library. The module takes a file path to an image alongside some parameters and returns a buffer. I seem to have come across a pretty bad memory leak issue which Massif reports as being related to either the buffer that is created or the Magick++ image. Here's my C++ code:
#include <napi.h>
#include <list>
#include <Magick++.h>
using namespace std;
using namespace Magick;
class FlipWorker : public Napi::AsyncWorker {
public:
FlipWorker(Napi::Function& callback, string in_path, bool flop, string type, int delay)
: Napi::AsyncWorker(callback), in_path(in_path), flop(flop), type(type), delay(delay) {}
~FlipWorker() {}
void Execute() {
list<Image> frames;
list<Image> coalesced;
list<Image> mid;
list<Image> result;
readImages(&frames, in_path);
coalesceImages(&coalesced, frames.begin(), frames.end());
for (Image &image : coalesced) {
flop ? image.flop() : image.flip();
image.magick(type);
mid.push_back(image);
}
optimizeImageLayers(&result, mid.begin(), mid.end());
if (delay != 0) for_each(result.begin(), result.end(), animationDelayImage(delay));
writeImages(result.begin(), result.end(), &blob);
}
void OnOK() {
Callback().Call({Env().Undefined(), Napi::Buffer<char>::Copy(Env(), (char *)blob.data(), blob.length())});
}
private:
string in_path, type;
bool flop;
int delay;
Blob blob;
};
Napi::Value Flip(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
Napi::Object obj = info[0].As<Napi::Object>();
Napi::Function cb = info[1].As<Napi::Function>();
string path = obj.Get("path").As<Napi::String>().Utf8Value();
bool flop = obj.Has("flop") ? obj.Get("flop").As<Napi::Boolean>().Value() : false;
string type = obj.Get("type").As<Napi::String>().Utf8Value();
int delay = obj.Get("delay").As<Napi::Number>().Int32Value();
FlipWorker* flipWorker = new FlipWorker(cb, path, flop, type, delay);
flipWorker->Queue();
return env.Undefined();
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "flip"), Napi::Function::New(env, Flip));
return exports;
}
NODE_API_MODULE(addon, Init);
And an example JS script:
const image = require("./build/Release/image.node");
setInterval(() => {
image.flip({ path: "/home/esm/animated.gif", type: "gif", delay: 0 }, (error, buffer) => {
console.log(buffer);
console.log(process.memoryUsage().rss);
});
}, 10000);
Here is a sample output of the script:
<Buffer 47 49 46 38 39 61 80 02 66 01 f7 00 00 38 44 3a 62 58 26 70 64 27 12 1c 4d 19 26 50 26 30 57 10 38 79 2c 37 67 35 51 57 14 47 79 35 4a 71 55 4f 4f 68 ... 868294 more bytes>
69496832
<Buffer 47 49 46 38 39 61 80 02 66 01 f7 00 00 38 44 3a 62 58 26 70 64 27 12 1c 4d 19 26 50 26 30 57 10 38 79 2c 37 67 35 51 57 14 47 79 35 4a 71 55 4f 4f 68 ... 868294 more bytes>
110673920
<Buffer 47 49 46 38 39 61 80 02 66 01 f7 00 00 38 44 3a 62 58 26 70 64 27 12 1c 4d 19 26 50 26 30 57 10 38 79 2c 37 67 35 51 57 14 47 79 35 4a 71 55 4f 4f 68 ... 868294 more bytes>
152092672
<Buffer 47 49 46 38 39 61 80 02 66 01 f7 00 00 38 44 3a 62 58 26 70 64 27 12 1c 4d 19 26 50 26 30 57 10 38 79 2c 37 67 35 51 57 14 47 79 35 4a 71 55 4f 4f 68 ... 868294 more bytes>
192970752
<Buffer 47 49 46 38 39 61 80 02 66 01 f7 00 00 38 44 3a 62 58 26 70 64 27 12 1c 4d 19 26 50 26 30 57 10 38 79 2c 37 67 35 51 57 14 47 79 35 4a 71 55 4f 4f 68 ... 868294 more bytes>
204517376
As you can see, the resident set size increases significantly each time the function is run. This happens with every image in any format that I use with it. How would I keep the code from leaking? Thanks in advance.
EDIT:
I did some more digging and it turns out that since the buffer is not created through JS, it isn't eligible for garbage collection in the same way. I'm now wondering whether or not it's possible to create a buffer that gets garbage collected by V8 and still provides the same data.
Related
I don't know why it is giving the wrong output(appending all remaining numbers in the string at last)can any pls help me out!!
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main()
{string str="08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00\
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65\
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91\
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80\
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50\
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70\
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21\
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72\
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95\
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92\
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57\
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58\
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40\
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66\
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69\
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36\
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16\
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54\
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48";
int cnt=0;
for(int i=0;str[i];i++)
{
if(str[i]!=' ')
{
str[cnt++]=str[i];
}
}
str[cnt] = '\0';
cout<<str<<endl;
}
This is how it is displaying as output
Thank you
Strings can be split (with any whitespace in between) "like this" -> "like" " " "this".
I.e. (guessing a little a the desired outcome):
string str=
"08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 "
"49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00 "
"81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65 "
"52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91 "
"22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80 "
"24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50 "
"32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70 "
"67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21 "
"24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72 "
"21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95 "
"78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92 "
"16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57 "
"86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58 "
"19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40 "
"04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66 "
"88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69 "
"04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36 "
"20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16 "
"20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54 "
"01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48 ";
No need for the line continuation here \<newline>, more of an obstacle.
Concerning the unexpected output of the rest of the string at the end:
Overwriting a letter with the '\0' does not have the terminating effect in a c++-string as it has in most character sequence handling functions in C.
As Botje mentions in the comments:
You overwrite 2/3 of the string, but what do you do with the remaining 1/3? You should truncate the string by either taking a substring or calling resize.
I.e. that is the way to change the effective length of a C++ string.
Not sure why you're trying to change str variable in place. Why don't you use a temporary string variable to do that?
Try this:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main() {
string str="08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 \
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00\
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65\
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91\
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80\
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50\
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70\
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21\
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72\
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95\
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92\
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57\
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58\
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40\
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66\
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69\
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36\
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16\
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54\
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48";
string tmp = "";
for(char& c : str) if(c != ' ') tmp += c;
str = tmp;
cout << str << endl;
}
So I've been staring at this for a while and I can't obviously see anything wrong, I'm grabbing a signedURL from my Lambda and then uploading to it using rn-fetch-blob.
Lambda Code is as follows:
export default async (event, context, callback, utils) => {
const { imageName } = JSON.parse(event.body)
console.log('imageName', imageName)
// These access keys relate to a user with AdministratorAccess
utils.AWS.config.update({
accessKeyId: 'XXXXX',
secretAccessKey: 'XXXXXXX',
})
let s3 = new utils.AWS.S3({ signatureVersion: 'v4' })
let params = { Bucket: 'MY_BUCKET', Key: imageName, Expires: 60, ContentType: 'image/jpeg' }
let url = await s3.getSignedUrl('putObject', params)
callback(null, utils.responder.success({ url.data.url }))
}
React native code is as follows:
const uploadImageToS3Endpoint = (s3Url, imageUrl) => {
var source = imageUrl.replace('file://', '')
return RNFetchBlob.fetch('POST', s3Url, {
'Content-Type': 'image/jpeg'
}, RNFetchBlob.wrap(source))
}
I get back(along with a load of other stuff, edited for brevity)
The request signature we calculated does not match the signature you provided. Check your key and signing method.
I did also try allocating public write to the S3 bucket to prove out it wasn't a permissions issue, still got the same result. Any advice would be greatly appreciated as this should be simple!
EDIT
AWS Response RN Fetch
"<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>THE_KEY</AWSAccessKeyId><StringToSign>AWS4-HMAC-SHA256
20181230T120956Z
20181230/eu-west-2/s3/aws4_request
b7b755c6335c0401711fafa241bbd816b5c7ad225c41cc324b0daaac2ee9f587</StringToSign><SignatureProvided>5345073e95a1dd39fa28f0a3c5c7350b2d7da75a5dedf3c2a895fdbd0e354961</SignatureProvided><StringToSignBytes>41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 0a 32 30 31 38 31 32 33 30 54 31 32 30 39 35 36 5a 0a 32 30 31 38 31 32 33 30 2f 65 75 2d 77 65 73 74 2d 32 2f 73 33 2f 61 77 73 34 5f 72 65 71 75 65 73 74 0a 62 37 62 37 35 35 63 36 33 33 35 63 30 34 30 31 37 31 31 66 61 66 61 32 34 31 62 62 64 38 31 36 62 35 63 37 61 64 32 32 35 63 34 31 63 63 33 32 34 62 30 64 61 61 61 63 32 65 65 39 66 35 38 37</StringToSignBytes><CanonicalRequest>POST
/C1E2DB45-CB94-4D3C-AEA7-C1CE4B42FCF1.jpg
Content-Type=image%2Fjpeg&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAJMVYRTCLXJGL2JGQ%2F20181230%2Feu-west-2%2Fs3%2Faws4_request&X-Amz-Date=20181230T120956Z&X-Amz-Expires=60&X-Amz-SignedHeaders=host
host:tthsshopproductimages.s3.eu-west-2.amazonaws.com
host
UNSIGNED-PAYLOAD</CanonicalRequest><CanonicalRequestBytes>50 4f 53 54 0a 2f 43 31 45 32 44 42 34 35 2d 43 42 39 34 2d 34 44 33 43 2d 41 45 41 37 2d 43 31 43 45 34 42 34 32 46 43 46 31 2e 6a 70 67 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3d 69 6d 61 67 65 25 32 46 6a 70 65 67 26 58 2d 41 6d 7a 2d 41 6c 67 6f 72 69 74 68 6d 3d 41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 26 58 2d 41 6d 7a 2d 43 72 65 64 65 6e 74 69 61 6c 3d 41 4b 49 41 4a 4d 56 59 52 54 43 4c 58 4a 47 4c 32 4a 47 51 25 32 46 32 30 31 38 31 32 33 30 25 32 46 65 75 2d 77 65 73 74 2d 32 25 32 46 73 33 25 32 46 61 77 73 34 5f 72 65 71 75 65 73 74 26 58 2d 41 6d 7a 2d 44 61 74 65 3d 32 30 31 38 31 32 33 30 54 31 32 30 39 35 36 5a 26 58 2d 41 6d 7a 2d 45 78 70 69 72 65 73 3d 36 30 26 58 2d 41 6d 7a 2d 53 69 67 6e 65 64 48 65 61 64 65 72 73 3d 68 6f 73 74 0a 68 6f 73 74 3a 74 74 68 73 73 68 6f 70 70 72 6f 64 75 63 74 69 6d 61 67 65 73 2e 73 33 2e 65 75 2d 77 65 73 74 2d 32 2e 61 6d 61 7a 6f 6e 61 77 73 2e 63 6f 6d 0a 0a 68 6f 73 74 0a 55 4e 53 49 47 4e 45 44 2d 50 41 59 4c 4f 41 44</CanonicalRequestBytes><RequestId>4E4DFD848923AC27</RequestId><HostId>DljdK6KPnzAeXxwUyYu32gb4g4JRI8kDTsdqZVqcM3wLYBsZ6kfT8UGZq6FI5/VimHdY6iL8eKg=</HostId></Error>"
RNFetchBlob.fetch(
'PUT',
link,
{
'Content-Type': undefined
},
RNFetchBlob.wrap(Platform.OS === "android" ? this.selectedImage.uri : this.selectedImage.uri.replace("file://", "")),
)
.then((resp) => {
console.log("Response data", resp)
this.onImageUploadSuccess(resp)
}).catch((err) => {
this.onUploadFailure(err)
})
This works for me
I try to send header frame and data frame with HPACK, and I received goaway frame with COMPRESSION_ERROR (0x9) from APNS.
my step:
send setting frame
recv setting frame
send ACK
recv ACK
send header frame
send data frame
requset:
HEADERS
- END_STREAM
+ END_HEADERS
:method = POST
:scheme = https
:path = /3/device/ad92823c9e42e37241b6cdf6f583c6cdf5dcc21289c57fb6641213abeff8095d
host = api.development.push.apple.com
DATA
+ END_STREAM
{ "aps" : { "alert" : "Hello" } }
Hex:
00 00 77 01 04 00 00 00 01 HEADER FRAME
83 :method = POST
86 :scheme = https
04 :path = (Literal Header Field without Indexing)
4a length(74)
2f 33 2f 64 65 76 69 63 /3/device/ad92823c9e42e37241b6cdf6f583c6cdf5dcc21289c57fb6641213abeff8095d
65 2f 61 64 39 32 38 32
33 63 39 65 34 32 65 33
37 32 34 31 62 36 63 64
66 36 66 35 38 33 63 36
63 64 66 35 64 63 63 32
31 32 38 39 63 35 37 66
62 36 36 34 31 32 31 33
61 62 65 66 66 38 30 39
35 64
66 host =
1e length(30)
61 70 69 2e 64 65 76 65 api.development.psuh.apple.com
6c 6f 70 6d 65 6e 74 2e
70 75 73 68 2e 61 70 70
6c 65 2e 63 6f 6d
00 00 21 00 01 00 00 00 01 DATA FRAME
7b 20 22 61 70 73 22 20 { "aps" : { "alert" : "hello" } }
3a 20 7b 20 22 61 6c 65
72 74 22 20 3a 20 22 68
65 6c 6c 6f 22 20 7d 20
7d
any tips?
thanks
I was wondering if there was a way to construct a grid or 2D array with predetermined numbers. Specifically, problem 11 of project Euler presents the following 20x20 grid:
08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48
And I'm trying to recreate it in code.
Thank you!
Sure:
int a[3][3] = { { 1, 2, 3},
{ 4, 5, 6},
{ 7, 8, 9} };
You're actually allowed to flatten the brace initializer out into a single run of numbers, but it's nice to be clear. In C99 and C++11 you can also have extraneous trailing commas.
This is the text of my program:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
int main(){
string line;
ifstream inf("grid.txt");
while(!inf.eof()){
getline(inf, line);
cout << line;
}
return 0;
}
(I'll be using sstream later)
This is the contents of grid.txt:
08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48
I'm compiling this under Cygwin and g++ and here's what I get:
$ g++ program.cpp
$ ./a.exe
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48
To save you looking - that's the last line of the file. If I replace the loop with:
getline(inf, line);
cout << line;
getline(inf, line);
cout << line;
it will display not the first, but the second line of the file. It's been a while since I've last programmed in C++ but I'm 90% sure it's supposed to display more than one line there...
Try adding a std::endl, which will automatically append a newline and flush the buffer.
You can also use the istream& getline ( istream& is, string& str, char delim ); signature to specify another delimiter than the default which is newline in case your file doesn't have any.
What file format is your grid.txt? It's likely that your lines end with a carriage return \r
Just as I finished asking my question I tried:
cout << "hi";
before changing it to the two couts. When I got two extra characters, that's when I realized I was getting the \r character. (Can you tell I've ran into problems with the carriage return before? :P )
You're not emitting a newline at the end of the lines, so they're overwriting each other.
Change the output line to
cout << line << endl;
You're reading binary data using getline. Try using read() instead.